【bzoj3673】可持久化并查集 by zky

Time Limit: 5 Sec Memory Limit: 128 MB

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

 

用可持久化线段树来可持久化数组以达到可持久化并查集的作用,有点像绕口令。。。

要注意的就是并查集的find也要在树上找到那个位置,使用它的位置,所以复杂度应该是两个log的,n logn logn 一次AC

 1 #include<bits/stdc++.h>
 2 #define maxn 20005
 3 #define mae 800005
 4 using namespace std;
 5 int n,m,root[maxn],l[mae],r[mae],cnt,fa[mae],rank[mae],L[mae],R[mae];
 6 void build(int& k,int le,int ri){
 7     if(!k) k=++cnt;L[k]=le;R[k]=ri;
 8     if(le==ri){fa[k]=le;rank[k]=0;return;}
 9     int mid=le+ri>>1;
10     build(l[k],le,mid);build(r[k],mid+1,ri);
11 }
12 void newly(int &k,int wi,int f,int h){
13     k=++cnt;
14     L[k]=L[wi];R[k]=R[wi];
15     if(L[k]==R[k]){fa[k]=h;return;}
16     l[k]=l[wi];r[k]=r[wi];
17     int mid=L[k]+R[k]>>1;
18     if(f<=mid) newly(l[k],l[wi],f,h);
19     else newly(r[k],r[wi],f,h);
20 }
21 int find(int k,int x){
22     if(L[k]==R[k]) return k;
23     int mid=L[k]+R[k]>>1;
24     if(x<=mid) return find(l[k],x);
25     else return find(r[k],x);
26 }
27 int fi(int x,int k){
28     k=find(root[x],k);
29     if(fa[k]!=L[k]) return fi(x,fa[k]);
30     return fa[k];
31 }
32 int main(){
33     scanf("%d%d",&n,&m);
34     build(root[0],1,n);int a,b,c,f,h;
35     for(int i=1;i<=m;i++){
36         scanf("%d",&a);
37         if(a==1){
38             scanf("%d%d",&b,&c);
39             f=fi(i-1,b);h=fi(i-1,c);
40             if(rank[f]<rank[h]) newly(root[i],root[i-1],f,h);
41             else{
42                 if(rank[f]>rank[h]) newly(root[i],root[i-1],h,f);
43                 else {newly(root[i],root[i-1],f,h);rank[find(root[i],f)]++;}
44             }
45         }
46         if(a==2) scanf("%d",&b),root[i]=root[b];
47         if(a==3){
48             scanf("%d%d",&b,&c);root[i]=root[i-1];
49             f=fi(i,b);h=fi(i,c);
50             if(f==h) printf("1\n");
51             else printf("0\n");
52         }
53     }
54     return 0;
55 }

 

转载于:https://www.cnblogs.com/awipppp/p/5959517.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值