bzoj 3673: 可持久化并查集 by zky

Time Limit: 5 Sec  Memory Limit: 128 MB
Submit: 1229  Solved: 561
[Submit][Status][Discuss]

Description

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

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

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
 
题解:
  用可持久化线段树维护并查集的信息,每棵线段树的叶子节点的fa值就是在当前线段树的时间下这个叶子节点表示的集合所在的根集合。查找操作就是不断地找叶子节点,如果这个叶子节点维护的fa值不是自己,就回到根节点找他fa的fa。
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstdlib>
 4 #include<cstring>
 5 #include<algorithm>
 6 #include<cmath>
 7 #include<vector>
 8 #include<queue>
 9 using namespace std;
10 const int maxn=3*1e4;
11 int N,M;
12 struct Tree{
13     int lc,rc,fa;
14 }tr[40*maxn];
15 int root[maxn],siz;
16 inline void build(int &i,int l,int r){
17     i=++siz;
18     if(l==r){
19         tr[i].fa=l; return ;
20     }
21     int mid=(l+r)>>1;
22     if(l<=mid) build(tr[i].lc,l,mid);
23     if(mid+1<=r) build(tr[i].rc,mid+1,r);
24 }
25 inline void change(int last,int &i,int l,int r,int pos,int now){
26     i=++siz;
27     tr[i].lc=tr[last].lc; tr[i].rc=tr[last].rc;
28     if(l==r){
29         tr[i].fa=now; return ;
30     }
31     int mid=(l+r)>>1;
32     if(pos<=mid) change(tr[last].lc,tr[i].lc,l,mid,pos,now);
33     else change(tr[last].rc,tr[i].rc,mid+1,r,pos,now);
34 }
35 inline int query(int i,int l,int r,int pos){//返回叶节点为 pos的节点编号 
36     if(l==r) return i;
37     int mid=(l+r)>>1;
38     if(pos<=mid) query(tr[i].lc,l,mid,pos);
39     else query(tr[i].rc,mid+1,r,pos);
40 }
41 inline int find(int i,int pos){//找到pos所在集合的根节点 
42     int x=query(i,1,N,pos);
43     if(tr[x].fa==pos) return x;
44     return find(i,tr[x].fa); 
45 }
46 int main(){
47     scanf("%d%d",&N,&M);
48     build(root[0],1,N);//初始化 
49     for(int i=1,kin,a,b;i<=M;i++){
50         scanf("%d",&kin);
51         if(kin==1){//合并 a b
52             root[i]=root[i-1];
53             scanf("%d%d",&a,&b);
54             int p=find(root[i],a),q=find(root[i],b);
55             if(tr[p].fa!=tr[q].fa){
56                 change(root[i-1],root[i],1,N,tr[p].fa,tr[q].fa);
57             }
58         }
59         else if(kin==2){//回到第a次操作前 
60             scanf("%d",&a);
61             root[i]=root[a];
62         }
63         else if(kin==3){//判断是否在同一集合 
64             root[i]=root[i-1];
65             scanf("%d%d",&a,&b);
66             int p=find(root[i],a),q=find(root[i],b);
67             if(tr[p].fa==tr[q].fa) puts("1");
68             else puts("0");
69         }
70     }
71     return 0;
72 }

 

posted @ 2016-03-03 17:16  CXCXCXC  阅读(183)  评论(0编辑  收藏  举报