zoukankan      html  css  js  c++  java
  • [BZOJ4444] [Luogu 4155] [LOJ 2007] [SCOI2015]国旗计划(倍增)

    [BZOJ4444] [Luogu 4155] [LOJ 2007] [SCOI2015]国旗计划(倍增)

    题面

    题面较长,略

    分析

    首先套路的断环为链。对于从l到r的环上区间,若l<=r,我们把它断成两个区间([l,r],[l+M,r+M]),否则断成([l,r+M],[l+M,r+M+M])(断成([l+M,2M])也可以)

    然后定义从区间[l,r]走到另一个与它相交的区间为1“步”。那么我们可以预处理出区间i走j步能够到达的区间右端点的最大值。注意到区间互不包含,先把区间按左端点为第一关键字,右端点为第二关键字排序。对于区间i,我们找到满足(l_i<l_j leq r_i)的最大(l_j),那么(r_j)就是走1步能到达的最大区间右端点。因为(l_j>l_i),所以(r_j>r_i),否则区间j就会被i包含。由于排序过,j显然有单调性,双指针扫一遍就可以了。

    	sort(a+1,a+1+sz);
    	int ptr=1;
    	for(int i=1;i<=sz;i++){
    		while(ptr<sz&&a[ptr+1].l<=a[i].r) ptr++;
    		if(ptr!=i) anc[i][0]=ptr;
    	}
    

    但是枚举走j步依然是(O(n^2))的,可以用倍增优化。(anc[i][j])表示区间i走j步到达的右端点最大的区间编号。这个可以(O(n log n))预处理。

    查询的时候从i开始跳,一直跳到(r_{anc[i][j]}geq l_i+M)为止,需注意边界条件

    int query(int x){
    	int ans=1;
    	int r=a[x].l+len; //注意边界,比如3->5,5->1,1->3.必须要跳回原点3,所以是+len而不是+len-1 
    	for(int i=log2n;i>=0;i--){
    		if(anc[x][i]!=0&&a[anc[x][i]].r<=r){//如果右端点<=i+M,就继续跳
    			ans+=(1<<i); 
    			x=anc[x][i];
    		}
    	}
    	if(anc[x][0]&&a[x].r<r){//上面求的是右端点<=i+M,可能跳到了<i+M的某一个位置,再跳一步就超过i+M,这种情况也是合法的。特判一下。
    		ans++;
    		x=anc[x][0];
    	}
    	return ans; //保证一定有解,所以不用判断a[x].r是否>=r
    }
    

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring> 
    #include<cmath>
    #include<algorithm> 
    #define INF 0x3f3f3f3f
    #define maxn 2000000
    #define maxlogn 25
    using namespace std;
    int n,len;
    struct seg{
    	int l;
    	int r;
    	int id;
    	seg(){
    		
    	}
    	seg(int _l,int _r,int _id){
    		l=_l;
    		r=_r;
    		id=_id;
    	}
    	friend bool operator  < (seg p,seg q){
    		if(p.l==q.l) return p.r<q.r;
    		else return p.l<q.l;
    	}
    }a[maxn+5]; 
    int sz;
    int log2n; 
    int ans[maxn+5];
    int anc[maxn+5][maxlogn+5];
    
    int query(int x){
    	int ans=1;
    	int r=a[x].l+len; //注意边界,比如3->5,5->1,1->3.必须要跳回原点3,所以是+len而不是+len-1 
    	for(int i=log2n;i>=0;i--){
    		if(anc[x][i]!=0&&a[anc[x][i]].r<=r){
    			ans+=(1<<i); 
    			x=anc[x][i];
    		}
    	}
    	if(anc[x][0]&&a[x].r<r){
    		ans++;
    		x=anc[x][0];
    	}
    	return ans; 
    }
    int main(){
    	int l,r;
    	scanf("%d %d",&n,&len);
    	log2n=log2(n*2);
    	for(int i=1;i<=n;i++){
    		scanf("%d %d",&l,&r);
    		if(l<=r){
    			a[++sz]=seg(l,r,i);
    			a[++sz]=seg(l+len,r+len,i+n);
    		}else{
    			a[++sz]=seg(l,r+len,i);
    			a[++sz]=seg(l+len,r+len+len,i+n);
    		}
    	}
    	sort(a+1,a+1+sz);
    	int ptr=1;
    	for(int i=1;i<=sz;i++){
    		while(ptr<sz&&a[ptr+1].l<=a[i].r) ptr++;
    		if(ptr!=i) anc[i][0]=ptr;
    	}
    	for(int j=1;j<=log2n;j++){
    		for(int i=1;i<=sz;i++){
    			anc[i][j]=anc[anc[i][j-1]][j-1];
    		}
    	}
    	for(int i=1;i<=sz;i++){
    		if(a[i].id<=n) ans[a[i].id]=query(i);//注意要跳过(l+n,r+n),否则l+len会超过2*len导致答案错误 
    	}
    	for(int i=1;i<=n;i++) printf("%d ",ans[i]);
    }
    
    
  • 相关阅读:
    Papervision3D Essentials中文版,附Papervision3D_2.1.920.swc和章节练习源码
    谷歌Chrome浏览器上安装调试(debugger)版本的Flash Player
    Flash运行时错误代码解释说明
    XML
    Android手机与电脑互通
    mysql
    j2ee
    Linux
    C_obj
    maven
  • 原文地址:https://www.cnblogs.com/birchtree/p/11518927.html
Copyright © 2011-2022 走看看