可撤销并查集——个人理解与学习笔记
网上有很多博客都是只放了一个代码,然后让读者自己解读代码,这里我写点自己的理解。
撤销的是什么?撤销的是操作。
如果我们让u和v链接,那么实际上是u和v的祖先是不同的,那么也就是fu = fid(u), fv = fid(v),如果fu!=fv,那么我们就将这样的操作放入,并且考虑到下次需要撤销,所以需要存储上一次的信息:
存储信息(假设我们让fa[fu] = fv):
1.记录fa[fu]的原来的节点,存{fa[fu](指针), fa[fu](对应的值)};
2.如果改变了深度,也就是deep[fv]的值改变了,那么就需要考虑存储{deep[fv](指针), deep[fv](值)}。
于是,有的时候需要撤销两次,有时候需要撤销一次。
所以,根据以上的信息,我们可以先写出寻找祖先的函数:
int fid(int x) { return x == fa[x] ? x : fid(fa[x]); }
然后是合并函数
void Merge(int x, int y) { x = fid(x); y = fid(y); if(x == y) return; Stap[++Stop] = 1; if(deep[x] > deep[y]) swap(x, y); stk.push(MP(fa + x, fa[x])); fa[x] = y; if(deep[x] == deep[y]) { Stap[Stop]++; stk.push(MP(deep + y, deep[y])); deep[y]++; } }
然后是撤销函数
void Undo() { *stk.top().first = stk.top().second; stk.pop(); }
最后,我再放一个完整的
1 #include <iostream> 2 #include <cstdio> 3 #include <cmath> 4 #include <string> 5 #include <cstring> 6 #include <algorithm> 7 #include <limits> 8 #include <vector> 9 #include <stack> 10 #include <queue> 11 #include <set> 12 #include <map> 13 #include <bitset> 14 #include <unordered_map> 15 #include <unordered_set> 16 #define lowbit(x) ( x&(-x) ) 17 #define pi 3.141592653589793 18 #define e 2.718281828459045 19 #define INF 0x3f3f3f3f 20 #define HalF (l + r)>>1 21 #define lsn rt<<1 22 #define rsn rt<<1|1 23 #define Lson lsn, l, mid 24 #define Rson rsn, mid+1, r 25 #define QL Lson, ql, qr 26 #define QR Rson, ql, qr 27 #define myself rt, l, r 28 #define pii pair<int, int> 29 #define MP(a, b) make_pair(a, b) 30 using namespace std; 31 typedef unsigned long long ull; 32 typedef unsigned int uit; 33 typedef long long ll; 34 const int maxN = 1e5 + 7; 35 stack<pair<int * , int>> stk; 36 int fa[maxN], deep[maxN]; 37 int N, M; 38 void init() 39 { 40 for(int i = 1; i <= N; i++) { fa[i] = i; deep[i] = 0; } 41 } 42 int fid(int x) { return x == fa[x] ? x : fid(fa[x]); } 43 int Stap[maxN], Stop; 44 void Merge(int x, int y) 45 { 46 x = fid(x); y = fid(y); 47 if(x == y) return; 48 Stap[++Stop] = 1; 49 if(deep[x] > deep[y]) swap(x, y); 50 stk.push(MP(fa + x, fa[x])); 51 fa[x] = y; 52 if(deep[x] == deep[y]) 53 { 54 Stap[Stop]++; 55 stk.push(MP(deep + y, deep[y])); 56 deep[y]++; 57 } 58 } 59 void Undo() 60 { 61 *stk.top().first = stk.top().second; 62 stk.pop(); 63 } 64 int main() 65 { 66 scanf("%d%d", &N, &M); 67 init(); 68 Stop = 0; 69 for(int i = 1, op, u, v; i <= M; i++) 70 { 71 scanf("%d", &op); 72 if(op == 1) 73 { 74 scanf("%d%d", &u, &v); 75 Merge(u, v); 76 } 77 else if(op == 2) 78 { 79 while(Stap[Stop]--) Undo(); 80 Stop--; 81 } 82 else 83 { 84 scanf("%d%d", &u, &v); 85 u = fid(u); v = fid(v); 86 printf("%d\n", u == v); 87 } 88 } 89 return 0; 90 }