BZOJ2165:大楼 倍增+dp
BZOJ1098:[POI2007]办公楼biu 补图+链表+BFS

BZOJ2054:疯狂的馒头&BZOJ2375:疯狂的涂色

shinbokuow posted @ Dec 26, 2014 02:32:05 PM in BZOJ with tags 并查集 离线处理 , 777 阅读

 

题目大意:

一个长度为\(n\)的序列,进行\(m\)次操作,第\(i\)次将区间\([l_i,r_i]\)染成颜色\(i\).求最终每个位置被染成什么颜色.

思路:

倒着处理,那么我们只需将当前区间内没染色的染成当前的颜色即可.

那么我们事实上是要维护那些位置还没有染色.由于每次染色都是一段连续区间,我们用并查集不断合并即可.能够保证总的时间复杂度为\(O(n)\).

因此总的复杂度为\(O(m+n)\).

注意当所有位置全部染色后及时退出.

#include<cstdio>
#include<cstring>
#include<cctype>
#include<iostream>
#include<algorithm>
using namespace std;
 
typedef long long LL;
 
#define N 1000010
int r[N],v[N];
int find(int x){int q=x,rq;for(;x!=r[x];x=r[x]);for(;q!=x;q=rq)rq=r[q],r[q]=x;return x;}
int main(){
    #ifndef ONLINE_JUDGE
    freopen("tt.in","r",stdin);
    #endif
    int n,m,q,p;cin>>n>>m>>q>>p;
    register int i,j;for(i=1;i<=n+1;++i)r[i]=i;
    int L,R;
    for(i=m;i>=1;--i){
        L=((LL)i*p+q)%n+1,R=((LL)i*q+p)%n+1;if(L>R)swap(L,R);
        //printf("%d %d\n",L,R);
        for(j=find(L);j<=R;j=r[j]){
            if(!v[j])v[j]=i;
            r[j]=find(j+1);
        }
        if(find(1)==n+1)break;
    }
    for(i=1;i<=n;++i)printf("%d\n",v[i]);
    return 0;
}

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter