这是以前做的一道题。
并查集 <=>一个father数组,于是可持久化并查集 <=>可持久化数组。
然后数组如何可持久化呢?用可持久化线段树实现。
每次合并就等价于修改father数组的一个值,就是线段树点修改。
然后查询也是,查father数组中的一个值,就是线段树点查询。
要查询历史版本,就套上可持久化即可。
1 /************************************************************** 2 Problem: 3674 3 User: rausen 4 Language: C++ 5 Result: Accepted 6 Time:1496 ms 7 Memory:158228 kb 8 ****************************************************************/ 9 10 #include <cstdlib> 11 #include <cstdio> 12 #include <algorithm> 13 14 using namespace std; 15 16 struct segment{ 17 int ls, rs, v, dep; 18 } seg[10000000]; 19 int tot, last, m, n, root[300000]; 20 21 void build_seg(int &p, int l, int r){ 22 if (!p) p = ++tot; 23 if (l == r){ 24 seg[p].v = l; 25 return; 26 } 27 int m = (l + r) >> 1; 28 build_seg(seg[p].ls, l, m); 29 build_seg(seg[p].rs, m + 1, r); 30 } 31 32 void modify(int l, int r, int x, int &y, int pos, int val){ 33 y = ++tot; 34 if (l == r){ 35 seg[y].v = val; 36 return; 37 } 38 seg[y].ls = seg[x].ls; 39 seg[y].rs = seg[x].rs; 40 int m = (l + r) >> 1; 41 if (pos <= m) modify(l, m, seg[x].ls, seg[y].ls, pos, val); 42 else modify(m + 1, r, seg[x].rs, seg[y].rs, pos, val); 43 } 44 45 void add(int p, int l, int r, int pos){ 46 if (l == r){ 47 ++seg[p].dep; 48 return; 49 } 50 int m = (l + r) >> 1; 51 if (pos <= m) add(seg[p].ls, l, m, pos); 52 else add(seg[p].rs, m + 1, r, pos); 53 } 54 55 int query(int p, int l, int r, int pos){ 56 if (l == r) return p; 57 int m = (l + r) >> 1; 58 if (pos <= m) return query(seg[p].ls, l, m, pos); 59 else return query(seg[p].rs, m + 1, r, pos); 60 } 61 62 int find(int p, int x){ 63 int k = query(p, 1, n, x); 64 if (x == seg[k].v) return k; 65 int t = find(p, seg[k].v); 66 modify(1, n, p, p, seg[k].v, t); 67 return t; 68 } 69 70 int main(){ 71 scanf("%d %d ", &n, &m); 72 build_seg(root[0], 1, n); 73 int oper, x, y, p, q; 74 for(int i = 1; i <= m; ++i){ 75 scanf("%d", &oper); 76 if (oper == 1){ 77 scanf("%d%d", &x, &y); 78 x = x ^ last, y = y ^ last; 79 root[i] = root[i - 1]; 80 p = find(root[i], x), q = find(root[i], y); 81 if (seg[p].v == seg[q].v) continue; 82 if (seg[p].dep > seg[q].dep) swap(p, q); 83 modify(1, n, root[i - 1], root[i], seg[p].v, seg[q].v); 84 if (seg[p].dep == seg[q].dep) add(root[i], 1, n, seg[q].v); 85 } else if (oper == 2){ 86 scanf("%d", &x); 87 x = x ^ last; 88 root[i] = root[x]; 89 } else{ 90 scanf("%d%d", &x ,&y); 91 x = x ^ last, y = y ^ last; 92 root[i] = root[i - 1]; 93 p = find(root[i], x), q = find(root[i], y); 94 if (seg[p].v == seg[q].v) last = 1; else last = 0; 95 printf("%d ", last); 96 } 97 } 98 return 0; 99 }
(p.s. 作为一名典型的嘴巴选手,还是要Orz hzwer的程序!!!)