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

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

HINT

Source

出题人大S

【分析】

出题人给我滚出来!保证不打死你!

真是***了,你题意描述清楚点会死啊。。调了将近2个小时...结果是题目理解错了....尼玛返回也算作操作啊。

思路还是蛮简单的。

用主席树维护一下并查集的fa数组就行了。

按照这种说法树状数组也应该可以可持久化了

  1 /*
  2 唐代李商隐
  3 《无题·昨夜星辰昨夜风》
  4 
  5 昨夜星辰昨夜风,画楼西畔桂堂东。
  6 身无彩凤双飞翼,心有灵犀一点通。
  7 隔座送钩春酒暖,分曹射覆蜡灯红。
  8 嗟余听鼓应官去,走马兰台类转蓬。
  9 */
 10 #include <iostream>
 11 #include <cstdio>
 12 #include <algorithm>
 13 #include <cstring>
 14 #include <vector>
 15 #include <utility>
 16 #include <iomanip>
 17 #include <string>
 18 #include <cmath>
 19 #include <queue>
 20 #include <assert.h>
 21 #include <map>
 22 #include <ctime>
 23 #include <cstdlib>
 24 #include <stack>
 25 #define LOCAL
 26 const int MAXN = 20000 * 10 * 20 + 10;
 27 //const int MAXM = 20000 + 10;
 28 const int INF = 100000000;
 29 const int SIZE = 450;
 30 const int maxnode =  0x7fffffff + 10;
 31 using namespace std;
 32 int n, m;//n为元素总个数 
 33 struct SEGTREE{
 34        //路径压缩+启发式合并还要用主席树OAO 
 35        struct Node{
 36               Node *ch[2];
 37               int l, r;
 38               int num;//其实除了叶子节点其他都是打酱油的,num是该节点的fa值 
 39        }mem[MAXN], *root[200000 * 10 + 10];
 40        int tot;
 41        
 42        void init(){
 43             tot = 0;
 44             root[0] = NULL;
 45             for (int i = 1; i <= 200000 * 10; i++) root[i] = NULL;
 46             build(root[0], 1, n);
 47             //printf("%d %d\n", root[0]->ch[0]->l, root[0]->ch[0]->r);
 48        }
 49        Node *NEW(int l, int r){
 50             Node *p = &mem[tot++];
 51             p->l = l;
 52             p->r = r;
 53             p->num = -1;
 54             p->ch[0] = p->ch[1] = NULL;
 55             return p;
 56        } 
 57        void build(Node *&t, int l, int r){
 58             if (t == NULL){
 59                   t = NEW(l, r);
 60                   //不要返回 
 61             }
 62             if (l == r) return;
 63             int mid = (l + r) >> 1;
 64             build(t->ch[0], l, mid);
 65             build(t->ch[1], mid + 1, r);
 66        }
 67        //t为现在的数将x的num改为val 
 68        void insert(Node *&t, Node *&last, int x, int val){
 69             if (t == NULL){
 70                t = NEW(last->l, last->r);
 71             }
 72             if (t->l == x && t->r == x) {t->num = val; return;}
 73             int mid = (t->l + t->r) >>1;
 74             if (x <= mid){
 75                   insert(t->ch[0], last->ch[0], x, val);
 76                   t->ch[1] = last->ch[1];
 77             }
 78             if (x > mid){
 79                   insert(t->ch[1], last->ch[1], x, val);
 80                   t->ch[0] = last->ch[0];
 81             }
 82        }
 83        //直接修改,不是可持久化的,节省空间 
 84        /*void change(Node *&t, int x, int val){
 85             if (t->l == x && t->r == x) {t->num = val;return;}
 86             int mid = (t->l + t->r) >> 1;
 87             if (x <= mid) change(t->ch[0], x, val);
 88             if (x > mid) change(t->ch[1], x, val);
 89        }*/
 90        int get(int k, int x){//查找k时刻x的fa值 
 91            Node *t = root[k];
 92            while (1){
 93                  if (t->l == x && t->r == x) break;
 94                  int mid = (t->l + t->r) >> 1;
 95                  if (x <= mid) t = t->ch[0];
 96                  else t = t->ch[1];
 97            }
 98            return t->num;
 99        }
100 }A;
101 int data[MAXN];//真正的操作次数 
102 int cnt = 0;//cnt记录现在的状态 
103 int BIGCNT;
104 
105 int find(int x){
106     int tmp = A.get(cnt, x);
107     if (tmp < 0) return x;
108     else{
109          int tmp2 = find(tmp);
110          //A.insert(A.root[cnt + 1], A.root[cnt], x, tmp2);
111          //cnt++;
112          return tmp2;
113     }
114 }
115 //启发式合并 
116 void merge(int x, int y){
117     //分别代表真实数量 
118     int x_num = -A.get(cnt, x);
119     int y_num = -A.get(cnt ,y);
120     if (x_num > y_num){//将y合并到x上 
121        //这里可以可持久化了 
122        //A.root[cnt + 1] = NULL;
123        A.insert(A.root[BIGCNT + 1], A.root[cnt], x, -(x_num + y_num));
124        BIGCNT++;
125        //A.root[cnt + 1] = NULL;
126        A.insert(A.root[BIGCNT + 1], A.root[cnt], y, x);
127        BIGCNT++;
128     }else{
129        //A.root[cnt + 1] = NULL;
130        A.insert(A.root[BIGCNT + 1], A.root[cnt], y, -(x_num + y_num));
131        BIGCNT++;
132        //A.root[cnt + 1] = NULL;
133        A.insert(A.root[BIGCNT + 1], A.root[cnt], x, y);
134        BIGCNT++;
135        //printf("%d %d %d\n", x, y, find(x));
136     }
137 }
138 void work(){
139      int z = 1;//记录操作的
140      data[0] = 0; 
141      cnt = 0;
142      BIGCNT = 0;
143      scanf("%d%d", &n, &m); 
144      A.init();
145      for (int i = 1; i <= m; i++){
146          int t;
147          scanf("%d", &t);
148          if (t == 2){
149             int c;
150             scanf("%d", &c);//回到c时刻即操作之后 
151             if (c == 2)
152             printf("");
153             cnt = data[c];
154          }else if (t == 1){
155             int a, b;
156             scanf("%d%d", &a, &b);
157             int xa = find(a), xb = find(b);
158             if (xa == xb) {data[i] = cnt;continue;}
159             merge(xa, xb);
160             cnt = BIGCNT;
161          }else{
162             int a, b;
163             scanf("%d%d", &a, &b);
164             if (find(a) == find(b)) printf("1\n");
165             else printf("0\n"); 
166          } 
167          data[i] = cnt;
168      }
169      //printf("%d", data[6]);
170 }
171 
172 int main(){
173     
174    
175     work();
176     return 0;
177 }
View Code

 

posted @ 2015-03-13 15:56  TCtower  阅读(303)  评论(0编辑  收藏  举报