离线做法 / 并查集与主席树的结合
顾名思义,就是可持久化的并查集————即支持历史版本回溯的并查集。
比如NOI2018d1t1的两个log做法。
通常实现方法
离线做法
注意到按秩合并的并查集是支持撤销的(注意“撤销”和“删除”是两码事)。
于是与其他离线题目类似,在操作的拓扑图上顺序做下就行了(空间又小跑得还快)。
1 #include<bits/stdc++.h> 2 const int maxn = 100035; 3 const int maxm = 200035; 4 5 struct QRs 6 { 7 int opt,x,y; 8 }q[maxm]; 9 struct DSU 10 { 11 int top,stk[maxn],fa[maxn],tot[maxn]; 12 void init() 13 { 14 top = 0; 15 for (int i=1; i<maxn; i++) fa[i] = i, tot[i] = 1; 16 } 17 int get(int x){return x==fa[x]?x:get(fa[x]);} 18 void unions(int x, int y) 19 { 20 int fx = get(x), fy = get(y); 21 if (fx==fy) return; 22 if (tot[fx] < tot[fy]) std::swap(fx, fy); 23 fa[fy] = fx, tot[fx] += tot[fy]; 24 stk[++top] = fy; 25 } 26 void back(int t) 27 { 28 while (top > t) 29 { 30 int x = stk[top--]; 31 tot[fa[x]] -= tot[x], fa[x] = x; 32 } 33 } 34 }f; 35 int ans[maxm]; 36 int n,m; 37 int edgeTot,edges[maxm],nxt[maxm],head[maxm]; 38 39 inline int read() 40 { 41 char ch = getchar(); 42 int num = 0; 43 bool fl = 0; 44 for (; !isdigit(ch); ch = getchar()) 45 if (ch=='-') fl = 1; 46 for (; isdigit(ch); ch = getchar()) 47 num = (num<<1)+(num<<3)+ch-48; 48 if (fl) num = -num; 49 return num; 50 } 51 void addedge(int u, int v) 52 { 53 edges[++edgeTot] = v, nxt[edgeTot] = head[u], head[u] = edgeTot; 54 } 55 void dfs(int x) 56 { 57 int t = f.top; 58 if (q[x].opt==3) ans[x] = f.get(q[x].x)==f.get(q[x].y)?1:0; 59 if (q[x].opt==1) f.unions(q[x].x, q[x].y); 60 for (int i=head[x]; i!=-1; i=nxt[i]) 61 dfs(edges[i]); 62 f.back(t); 63 } 64 int main() 65 { 66 memset(head, -1, sizeof head); 67 n = read(), m = read(), f.init(); 68 for (int i=1; i<=m; i++) 69 { 70 q[i].opt = read(), q[i].x = read(); 71 if (q[i].opt==2) addedge(q[i].x, i); 72 else q[i].y = read(), addedge(i-1, i); 73 } 74 dfs(0); 75 for (int i=1; i<=m; i++) 76 if (q[i].opt==3) printf("%d\n",ans[i]); 77 return 0; 78 }