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

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 }
posted @ 2019-01-06 21:01  Refun  阅读(122)  评论(0编辑  收藏  举报