【可持久化并查集】BZOJ3673-可持久化并查集 by zky

颓了十多天别问我再干嘛,在补学校作业

啊,开学了……我的夏天……

【题目大意】

n个集合 m个操作
操作:
1 a b 合并a,b所在集合
2 k 回到第k次操作之后的状态(查询算作操作)
3 a b 询问a,b是否属于同一集合,是则输出1否则输出0

0<n,m<=2*10^4

【思路】

数组是可以利用线段树的形式可持久化的,方法和主席树一模一样。那么我们在可持久化数组的基础上加上并查集的操作就可以了。

每次合并操作,先查询要合并两个元素的父亲所在位置。方法是如果当前位置的v不等于它所代表的数组中的下标(不是当前下标),那么就继续find。其余操作并查集没有区别。

回到k次状态只要T[0]=T[k]即可。

查询是否属于一个集合也是找出父亲,直接判断即可,同并查集。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #define lson l,m
  6 #define rson m+1,r
  7 const int MAXN=325754;
  8 using namespace std;
  9 int T[MAXN],v[MAXN],h[MAXN],L[MAXN],R[MAXN];
 10 int cnt,m,n;
 11 
 12 int build(int l,int r)
 13 {
 14     int rt=++cnt;
 15     if (l==r) v[rt]=l;
 16     else
 17     {
 18         int m=(l+r)>>1;
 19         L[rt]=build(lson);
 20         R[rt]=build(rson);
 21     }
 22     return rt;
 23 }
 24 
 25 int query(int rt,int x,int l,int r)
 26 {
 27     if (l==r) return rt;
 28     int m=(l+r)>>1;
 29     if (x<=m) return query(L[rt],x,lson);
 30         else return query(R[rt],x,rson);
 31 }
 32 
 33 int find(int rt,int x)
 34 {
 35     int p=query(rt,x,1,n);
 36     if (x==v[p]) return p;
 37         else return find(rt,v[p]);
 38 }
 39 
 40 void update(int rt,int x,int l,int r)
 41 {
 42     if (l==r)
 43     {
 44         h[rt]++;
 45         return;
 46     }
 47     int m=(l+r)>>1;
 48     if (x<=m) update(L[rt],x,lson);
 49         else update(R[rt],x,rson);
 50 }
 51 
 52 int modify(int pre,int x,int y,int l,int r)
 53 {
 54     int rt=++cnt;
 55     if (l==r)
 56     {
 57         v[rt]=y;
 58         h[rt]=h[pre];//不要忘了秩 
 59         return rt;
 60     }
 61     L[rt]=L[pre],R[rt]=R[pre];
 62     int m=(l+r)>>1;
 63     if (x<=m) L[rt]=modify(L[pre],x,y,lson);
 64         else R[rt]=modify(R[pre],x,y,rson);
 65     return rt;
 66 }
 67 
 68 void union_set(int fa,int fb,int i)
 69 {
 70     if (h[fa]>h[fb]) swap(fa,fb);
 71     T[i]=modify(T[i-1],v[fa],v[fb],1,n);//注意这里是v[fa]而不是fa 
 72     if (h[fa]==h[fb]) update(T[i],v[fb],1,n);
 73 }
 74 
 75 void init()
 76 {
 77     cnt=0;
 78     scanf("%d%d",&n,&m);
 79     T[0]=build(1,n);
 80 }
 81 
 82 void solve()
 83 {
 84     for (int i=1;i<=m;i++)
 85     {
 86         int op,a,b;
 87         scanf("%d",&op);
 88         if (op==1)
 89         {
 90             scanf("%d%d",&a,&b);
 91             T[i]=T[i-1];
 92             int fa=find(T[i],a),fb=find(T[i],b);
 93             if (v[fa]!=v[fb]) union_set(fa,fb,i);
 94         }
 95         if (op==2)
 96         {
 97             scanf("%d",&a);
 98             T[i]=T[a];
 99         }
100         if (op==3)
101         {
102             scanf("%d%d",&a,&b);
103             T[i]=T[i-1];
104             int fa=find(T[i],a),fb=find(T[i],b);
105             if (v[fa]==v[fb]) puts("1");else puts("0");
106         }
107     }
108 }
109 
110 int main()
111 {
112     init();
113     solve(); 
114     return 0;
115 }
原文地址:https://www.cnblogs.com/iiyiyi/p/5824582.html