【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

 

你可能感兴趣的:(并查集)