BZOJ3673/3674:可持久化并查集
Description
n个集合 m个操作
操作:
1 a b 合并a,b所在集合
2 k 回到第k次操作之后的状态(查询算作操作)
3 a b 询问a,b是否属于同一集合,是则输出1否则输出0
0<n,m<=2*10^4
Input
Output
Sample Input
5 6
1 1 2
3 1 2
2 0
3 1 2
2 1
3 1 2
1 1 2
3 1 2
2 0
3 1 2
2 1
3 1 2
Sample Output
1
0
1
Solution
板子题……只不过网上有很多假做法。
具体做法就是整两个可持久化数组(不知道谁起的这么鬼畜的名字……我还是更喜欢叫他可持久化线段树)来记录并查集的$fa$数组和$dep$数组。因为路径压缩会破坏可持久化的结构,所以我们只能记录$dep$数组来按秩合并。
网上很多只搞了一颗可持久化线段树,维护$fa$就可持久化线段树$insert$一条链,维护$dep$就修改历史版本上的点的做法是错的……已经被卡掉了QAQ
Code
1 #include<iostream> 2 #include<cstdio> 3 #define N (200009) 4 using namespace std; 5 6 int n,m,lastans,opt,x,y; 7 8 struct Tree 9 { 10 struct Sgt{int ls,rs,v;}Segt[N*20]; 11 int sgt_num,a[N],Root[N]; 12 int Build(int l,int r) 13 { 14 int now=++sgt_num; 15 if (l==r) {Segt[now].v=a[l]; return now;} 16 int mid=(l+r)>>1; 17 Segt[now].ls=Build(l,mid); 18 Segt[now].rs=Build(mid+1,r); 19 return now; 20 } 21 int Update(int pre,int l,int r,int x,int v) 22 { 23 int now=++sgt_num; 24 Segt[now].ls=Segt[pre].ls; 25 Segt[now].rs=Segt[pre].rs; 26 if (l==r) {Segt[now].v=v; return now;} 27 int mid=(l+r)>>1; 28 if (x<=mid) Segt[now].ls=Update(Segt[now].ls,l,mid,x,v); 29 else Segt[now].rs=Update(Segt[now].rs,mid+1,r,x,v); 30 return now; 31 } 32 int Query(int now,int l,int r,int x) 33 { 34 if (l==r) return Segt[now].v; 35 int mid=(l+r)>>1; 36 if (x<=mid) return Query(Segt[now].ls,l,mid,x); 37 else return Query(Segt[now].rs,mid+1,r,x); 38 } 39 }CT[2]; 40 41 int Find(int x,int t) 42 { 43 int fa=CT[0].Query(CT[0].Root[t],1,n,x); 44 return x==fa?x:Find(fa,t); 45 } 46 47 int main() 48 { 49 scanf("%d%d",&n,&m); 50 for (int i=1; i<=n; ++i) 51 CT[0].a[i]=i, CT[1].a[i]=1; 52 CT[0].Root[0]=CT[0].Build(1,n); 53 CT[1].Root[0]=CT[1].Build(1,n); 54 for (int i=1; i<=m; ++i) 55 { 56 scanf("%d",&opt); 57 if (opt==1) 58 { 59 CT[0].Root[i]=CT[0].Root[i-1]; 60 CT[1].Root[i]=CT[1].Root[i-1]; 61 scanf("%d%d",&x,&y); 62 /*x^=lastans; y^=lastans;*/ 63 int fx=Find(x,i),fy=Find(y,i); 64 if (fx==fy) continue; 65 int dfx=CT[1].Query(CT[1].Root[i],1,n,fx); 66 int dfy=CT[1].Query(CT[1].Root[i],1,n,fy); 67 if (dfx>dfy) swap(fx,fy); 68 CT[0].Root[i]=CT[0].Update(CT[0].Root[i],1,n,fx,fy); 69 if (dfx!=dfy) continue; 70 CT[1].Root[i]=CT[1].Update(CT[1].Root[i],1,n,fy,dfy+1); 71 } 72 if (opt==2) 73 { 74 scanf("%d",&x); /*x^=lastans;*/ 75 CT[0].Root[i]=CT[0].Root[x]; 76 CT[1].Root[i]=CT[1].Root[x]; 77 } 78 if (opt==3) 79 { 80 CT[0].Root[i]=CT[0].Root[i-1]; 81 CT[1].Root[i]=CT[1].Root[i-1]; 82 scanf("%d%d",&x,&y); 83 /*x^=lastans; y^=lastans;*/ 84 int fx=Find(x,i),fy=Find(y,i); 85 if (fx==fy) puts("1")/*, lastans=1*/; 86 else puts("0")/*, lastans=0*/; 87 } 88 } 89 }