[BZOJ]3514: Codechef MARCH14 GERALD07加强版
Time Limit: 60 Sec Memory Limit: 256 MB
Description
N个点M条边的无向图,询问保留图中编号在[l,r]的边的时候图中的联通块个数。
Input
第一行四个整数N、M、K、type,代表点数、边数、询问数以及询问是否加密。
接下来M行,代表图中的每条边。
接下来K行,每行两个整数L、R代表一组询问。对于type=0的测试点,读入的L和R即为询问的L、R;对于type=1的测试点,每组询问的L、R应为L xor lastans和R xor lastans。
Output
K行每行一个整数代表该组询问的联通块个数。
Sample Input
3 5 4 0
1 3
1 2
2 1
3 2
2 2
2 3
1 5
5 5
1 2
1 3
1 2
2 1
3 2
2 2
2 3
1 5
5 5
1 2
Sample Output
2
1
3
1
1
3
1
HINT
对于100%的数据,1≤N、M、K≤200,000。
2016.2.26提高时限至60s
Solution
对每条边预处理出最右的询问左端点满足从这个左端点开始向右把边加入图中,加到这条边时该边的两个点已经在一个联通块内,可以这么做:从左到右把所有边加入图中,实时用LCT维护图的最大生成树(森林),其中边权为边的编号,每次若两个点未联通我们直接连(并且我们知道这条边没有满足条件的左端点),否则找到两点在树上的链中边权最小的边把它删掉,这条边的编号就是我们要求的左端点,然后再把新加的边连上,顺带一提,LCT维护边可以对每个点维护其到树上父亲和偏爱子节点的边的编号。预处理出这些之后回答询问就很容易了,我们把区间内的边数扣掉区间内求出的左端点在询问区间内的边(用主席树可以维护),用点数减掉这些边数即可。总复杂度O(nlogn),常数较大。
Code
#include<cstdio> #include<algorithm> using namespace std; char B[1<<26],*S=B,C;int X; inline int read() { while((C=*S++)<'0'||C>'9'); for(X=C-'0';(C=*S++)>='0'&&C<='9';)X=X*10+C-'0'; return X; } #define MN 200000 #define ND 4000000 #define L(x) c[x][0] #define R(x) c[x][1] int fa[MN+5],c[MN+5][2],tf[MN+5],tc[MN+5],mn[MN+5],rv[MN+5],z[MN+5],zn; struct node{int l,r,s;}t[ND+5]; int x[MN+5],y[MN+5],rt[MN+5],tn; inline bool isc(int x){return L(fa[x])==x||R(fa[x])==x;} inline int MiN(int a,int b){return a?b?min(a,b):a:b;} inline void up(int x){mn[x]=MiN(MiN(tf[x],tc[x]),MiN(mn[L(x)],mn[R(x)]));} inline void rev(int x){swap(L(x),R(x));swap(tf[x],tc[x]);rv[x]^=1;} inline void down(int x){if(rv[x])rev(L(x)),rev(R(x)),rv[x]=0;} void rotate(int x) { int f=fa[x],ff=fa[f],l=R(f)==x,r=l^1; if(isc(f))c[ff][R(ff)==f]=x; fa[f]=x;fa[x]=ff;fa[c[x][r]]=f; c[f][l]=c[x][r];up(c[x][r]=f); } void splay(int x) { for(int i=z[zn=1]=x;isc(i);)i=z[++zn]=fa[i]; while(zn)down(z[zn--]); for(int f;isc(x);rotate(x)) if(isc(f=fa[x]))rotate(L(fa[f])==f^L(f)==x?x:f); up(x); } void access(int x) { for(int i=0,it=0;x;x=fa[i=x]) { splay(x);tc[x]=tf[it];R(x)=i;up(x); for(it=x;L(it);)down(it),it=L(it); } } bool same(int x,int y) { access(x);splay(x);rev(x); access(y);splay(y); return isc(x); } void link(int x,int y,int i) { access(x);splay(x);rev(x); access(y);splay(y); fa[R(y)=x]=y;tf[x]=tc[y]=i; up(x);up(y); } void cut(int x,int y) { access(x);splay(x);rev(x); access(y);splay(y); L(y)=fa[x]=tc[x]=tf[y]=0; up(x);up(y); } int add(int k,int l,int r,int x) { int p=++tn,mid=l+r>>1; t[p].s=t[k].s+1; if(l<r)if(x<=mid)t[p].l=add(t[k].l,l,mid,x),t[p].r=t[k].r; else t[p].l=t[k].l,t[p].r=add(t[k].r,mid+1,r,x); return p; } int query(int kl,int kr,int l,int r,int ql,int qr) { if(l==ql&&r==qr)return t[kr].s-t[kl].s; int mid=l+r>>1; if(qr<=mid)return query(t[kl].l,t[kr].l,l,mid,ql,qr); if(ql>mid)return query(t[kl].r,t[kr].r,mid+1,r,ql,qr); return query(t[kl].l,t[kr].l,l,mid,ql,mid)+query(t[kl].r,t[kr].r,mid+1,r,mid+1,qr); } int main() { fread(B,1,1<<26,stdin); int m,n,k,t,i,j,l; m=read();n=read();k=read();t=read(); for(i=1;i<=n;++i) { x[i]=read();y[i]=read();rt[i]=rt[i-1]; if(x[i]==y[i]){rt[i]=add(rt[i],1,n,i);continue;} if(same(x[i],y[i]))rt[i]=add(rt[i],1,n,l=mn[y[i]]),cut(x[l],y[l]); link(x[i],y[i],i); } for(l=0;k--;t?0:l=0)i=read()^l,j=read()^l, printf("%d\n",l=m-j+i-1+query(rt[i-1],rt[j],1,n,i,j)); }