bzoj 3514: Codechef MARCH14 GERALD07加强版
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
Source
一开始看到这个题的时候第一眼想法就是暴力莫队+LCT,然而是强制在线QAQ。。。
然后就不会了,然后就颓了。。。根本想不到这题跟主席树有什么关系。。。
看了题解之后膝盖都给跪烂,Orz%%%
做法是这样的:
不断加边,如果产生了环,那么把环上编号最小的边给删掉,并且用ntr[i]记录该边把哪条边给删掉了。。。如果没删掉就是0;
对于每个l-r区间的询问查找这些边有多少边的ntr[i]<l(num),对于每个询问的答案为n-num;
这样为什么是对的呢???
对于一条边,如果ntr[i]>=l,那么他一定可以与l--r这个区间的边产生一个环。。。环的话对于连通块的数量是没有贡献的。
反之,如果一条边的ntr[i]<l,那么他肯定不可能与l--r这个区间中的边产生环,也就相当于这条边对于l--r这个区间是一条树边,而每一条树边的贡献相当于是减少一个连通块。。。
所以这样是有正确性的。。。
加边删边是可以用LCT实现的,注意使用把边当做点的技巧。。。
而查询区间中用小于l的边有多少个是可以用主席树实现的。。。
以下附代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 using namespace std; 6 const int N=400050; 7 const int INF=2147483647; 8 int gi() 9 { 10 int x=0; 11 char ch=getchar(); 12 while(ch<'0'||ch>'9') ch=getchar(); 13 while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); 14 return x; 15 } 16 int c[N][2],fa[N],minm[N],st[N],rev[N],root[N*20],s[N*20],sz,ls[N*20],rs[N*20],w[N]; 17 int n,m,k,type,ntr[N*2],last; 18 struct ac 19 { 20 int x,y,id; 21 }e[N]; 22 bool isroot(int x){return c[fa[x]][0]!=x&&c[fa[x]][1]!=x;} 23 void update(int x) 24 { 25 int l=c[x][0],r=c[x][1]; 26 minm[x]=x; 27 if(w[minm[x]]>w[minm[l]]) minm[x]=minm[l]; 28 if(w[minm[x]]>w[minm[r]]) minm[x]=minm[r]; 29 } 30 void pushdown(int x) 31 { 32 int l=c[x][0],r=c[x][1]; 33 if(rev[x]) 34 { 35 rev[x]^=1;rev[l]^=1;rev[r]^=1; 36 swap(c[x][0],c[x][1]); 37 } 38 } 39 void rotate(int x) 40 { 41 int y=fa[x],z=fa[y],l,r; 42 if(c[y][0]==x) l=0;else l=1;r=l^1; 43 if(!isroot(y)) 44 { 45 if(c[z][0]==y) c[z][0]=x; 46 else c[z][1]=x; 47 } 48 fa[y]=x;fa[x]=z;fa[c[x][r]]=y; 49 c[y][l]=c[x][r];c[x][r]=y; 50 update(y);update(x); 51 } 52 void splay(int x) 53 { 54 int top=0;st[++top]=x; 55 for(int i=x;!isroot(i);i=fa[i]) st[++top]=fa[i]; 56 for(int i=top;i;i--) pushdown(st[i]); 57 while(!isroot(x)) 58 { 59 int y=fa[x],z=fa[y]; 60 if(!isroot(y)) 61 { 62 if(c[y][0]==x^c[z][0]==y) rotate(x); 63 else rotate(y); 64 } 65 rotate(x); 66 } 67 } 68 void access(int x) 69 { 70 int t=0; 71 while(x) 72 { 73 splay(x); 74 c[x][1]=t; 75 t=x;update(x);x=fa[x]; 76 } 77 } 78 void rever(int x) {access(x),splay(x),rev[x]^=1;} 79 void lnk(int x,int y) {rever(x);fa[x]=y;} 80 void cut(int x,int y) {rever(x);access(y);splay(y);c[y][0]=fa[x]=0;} 81 int query1(int x,int y) {rever(x);access(y);splay(y);return minm[y];} 82 int find(int x) 83 { 84 access(x);splay(x); 85 while(c[x][0])x=c[x][0]; 86 return x; 87 } 88 void insert(int l,int r,int x,int &y,int v) 89 { 90 y=++sz;s[y]=s[x]+1; 91 ls[y]=ls[x];rs[y]=rs[x]; 92 if(l==r) return; 93 int mid=(l+r)>>1; 94 if(v<=mid) insert(l,mid,ls[x],ls[y],v); 95 else insert(mid+1,r,rs[x],rs[y],v); 96 } 97 int query(int l,int r,int x,int y,int v) 98 { 99 if(l==r) return s[y]-s[x]; 100 int mid=(l+r)>>1; 101 if(v<=mid) return query(l,mid,ls[x],ls[y],v); 102 else return s[ls[y]]-s[ls[x]]+query(mid+1,r,rs[x],rs[y],v); 103 } 104 void pre() 105 { 106 for(int i=1;i<=m;i++) 107 { 108 if(e[i].x==e[i].y) {ntr[i]=i;continue;} 109 if(find(e[i].x)!=find(e[i].y)) 110 { 111 w[n+i]=n+i;minm[n+i]=n+i; 112 lnk(n+i,e[i].x);lnk(n+i,e[i].y); 113 } 114 else if(find(e[i].x)==find(e[i].y)) 115 { 116 int mm=query1(e[i].x,e[i].y);ntr[i]=mm-n; 117 cut(e[mm-n].x,mm);cut(e[mm-n].y,mm); 118 w[n+i]=i+n;minm[n+i]=n+i; 119 lnk(e[i].x,n+i);lnk(e[i].y,n+i); 120 } 121 } 122 for(int i=1;i<=m;i++) insert(0,m,root[i-1],root[i],ntr[i]); 123 } 124 void work() 125 { 126 int l,r; 127 for(int i=1;i<=k;i++) 128 { 129 l=gi();r=gi(); 130 if(type) l^=last,r^=last; 131 last=n-query(0,m,root[l-1],root[r],l-1); 132 printf("%d\n",last); 133 } 134 } 135 int main() 136 { 137 n=gi();m=gi();k=gi();type=gi(); 138 for(int i=1;i<=m;i++) e[i].x=gi(),e[i].y=gi(),e[i].id=i; 139 w[0]=INF; 140 for(int i=1;i<=n;i++) w[i]=INF,minm[i]=i; 141 pre(); 142 work(); 143 return 0; 144 }