zoukankan      html  css  js  c++  java
  • 【BZOJ4444】国旗计划

    Description

      
       题目链接
      
      
      

    Solution

    磕了3个半小时没做出来的题,就是全场崩.
      
       首先对于一个人的答案是很好求的,显然是选择左端点在此人区间中,右端点最远(最靠右)的人作为下一个接棒人.因此用线段树维护一下就可以了,注意判断跨环边界的情况(n->1).
      
       时间复杂度$ mathcal O(n^2 log n) $.
      
       接着我再想,如果按左端点从大到小从右往左注意处理,每个人其实就是选择那些左端点处于自己区间中的人作为后继,选择它们的答案最小值即可.然而终止点也是不断移动的,所以每个人的答案在之后的人看是动态的.考虑很难修改,就猜性质,猜了个性质,用2h实现程序暴力和数据生成器,然后一组数据见祖宗.
      
       TMD

      
       稍微换一下思路,与其想办法维护接力方案,不如直接考虑计算每个人,并优化这个过程.
      
       可以发现,每个人选择哪一个人作为下一棒是唯一确定的(左端点在区间内的人中,右端点最远的那个人). 且每传一次棒,贡献的距离也是唯一确定的(当前人的右端点与下一棒的右端点的距离).
      
       确定下一棒可以用线段树直接模拟.
      
       对于每个人(i),我们相当于要知道从他开始至少传多少棒之后,总距离贡献超过了(m-len_i). 其中(len_i)表示这个人的区间长度减一.
      
       那么倍增出传(2^k)步后是谁,以及总距离贡献是多少.
      
       对于每个人直接从大到小枚举(k)逐步逼近目标步数即可.
      
       总时间复杂度是(mathcal O (n log n))
      
      
      

    Code

      

    #include <cstdio>
    #include <algorithm>
    #define mp make_pair
    using namespace std;
    typedef pair<int,int> pii;
    typedef long long ll;
    const int N=200005;
    const int INF=1e9;
    int n,m;
    int diz[N*2],dcnt,who[N*2];
    int go[N][19];
    ll d[N][19];
    struct Man{
    	int l,r,id;
    	int get(){
    		if(l<r) return r-l;
    		return r+(dcnt-l);
    	}
    }p[N];
    void readData(){
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;i++){
    		scanf("%d%d",&p[i].l,&p[i].r);
    		p[i].id=i;
    	}
    }
    void Diz(){
    	for(int i=1;i<=n;i++){
    		diz[++dcnt]=p[i].l; 
    		diz[++dcnt]=p[i].r;
    	}
    	sort(diz+1,diz+1+dcnt);
    	dcnt=unique(diz+1,diz+1+dcnt)-diz-1;
    	for(int i=1;i<=n;i++){
    		p[i].l=lower_bound(diz+1,diz+1+dcnt,p[i].l)-diz;
    		p[i].r=lower_bound(diz+1,diz+1+dcnt,p[i].r)-diz;
    	}
    }
    bool cmpMan(const Man &a,const Man &b){
    	return a.l<b.l;
    }
    pii max(pii x,pii y){
    	return x.first>y.first?x:y;
    }
    namespace SEG{/*{{{*/
    	const int S=N*4;
    	int rt,sz;
    	int ch[S][2];
    	pii info[S];
    	inline void pushup(int u){
    		info[u]=max(info[ch[u][0]],info[ch[u][1]]);
    	}
    	void build(int &u,int l,int r){
    		u=++sz;
    		if(l==r){
    			info[u]=mp(-INF,-INF);
    			return;
    		}
    		int mid=(l+r)>>1;
    		build(ch[u][0],l,mid);
    		build(ch[u][1],mid+1,r);
    		pushup(u);
    	}
    	void modify(int u,int l,int r,int pos,pii val){
    		if(l==r){
    			info[u]=val;
    			return;
    		}
    		int mid=(l+r)>>1;
    		if(pos<=mid)
    			modify(ch[u][0],l,mid,pos,val);
    		else
    			modify(ch[u][1],mid+1,r,pos,val);
    		pushup(u);
    	}
    	pii query(int u,int l,int r,int L,int R){
    		if(L<=l&&r<=R) return info[u];
    		int mid=(l+r)>>1;
    		if(R<=mid) return query(ch[u][0],l,mid,L,R);
    		else if(mid<L) return query(ch[u][1],mid+1,r,L,R);
    		else
    			return max(query(ch[u][0],l,mid,L,mid),query(ch[u][1],mid+1,r,mid+1,R));
    	}
    }/*}}}*/
    void calc(){
    	SEG::build(SEG::rt,1,dcnt);
    	for(int i=1;i<=n;i++)
    		SEG::modify(SEG::rt,1,dcnt,p[i].l,mp(p[i].l>p[i].r?p[i].r+dcnt:p[i].r,i));
    	for(int i=1;i<=n;i++){
    		int x;
    		pii get;
    		if(p[i].l<p[i].r)
    			get=SEG::query(SEG::rt,1,dcnt,p[i].l+1,p[i].r);
    		else{
    			get=mp(-INF,-INF);
    			if(p[i].l<dcnt)
    				get=SEG::query(SEG::rt,1,dcnt,p[i].l+1,dcnt);
    			pii tmp=SEG::query(SEG::rt,1,dcnt,1,p[i].r);
    			tmp.first+=dcnt;
    			get=max(get,tmp);
    		}
    		go[i][0]=get.second;
    		d[i][0]=get.first-(p[i].l>p[i].r?p[i].r+dcnt:p[i].r);
    	}
    	for(int j=1;j<=18;j++)
    		for(int u=1;u<=n;u++){
    			go[u][j]=go[go[u][j-1]][j-1];
    			d[u][j]=d[u][j-1]+d[go[u][j-1]][j-1];
    		}
    }
    void solve(){
    	for(int i=1;i<=n;i++){
    		int ans=1;
    		int u=i,last=dcnt-p[i].get();
    		for(int j=18;j>=0;j--)
    			if(d[u][j]<last){
    				last-=d[u][j];
    				ans+=(1<<j);
    				u=go[u][j];
    			}
    		printf("%d ",ans+1);
    	}
    	puts("");
    }
    int main(){
    	readData();
    	Diz();
    	calc();
    	solve();
    	return 0;
    }
    
  • 相关阅读:
    字节序(Endian),大端(BigEndian),小端(LittleEndian)
    关于PHOTO SHOP CS9.0无法启动adobe updater 请重新安装应用程序和组件解决方法!
    工作·事业·人生
    多选列表Select之双击删除与添加Demo
    WIN7任务栏修复解决windows7任务栏不能停靠图标的问题
    ip地址被绑定,vmware无法共享上网,
    小屋·小篮子·祭
    基础知识提问:关于HashTable和List两个容器Add改变了属性的同一对象的问题
    [转载]正则表达式30分钟入门教程及MTracer(破解版)
    让程序更健壮,用错误还是抛异常?
  • 原文地址:https://www.cnblogs.com/RogerDTZ/p/9518208.html
Copyright © 2011-2022 走看看