【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
1 1 2
3 1 2
2 0
3 1 2
2 1
3 1 2
Sample Output
1
0
1
0
1
HINT
Source
【分析】
出题人给我滚出来!保证不打死你!
真是***了,你题意描述清楚点会死啊。。调了将近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 }