题意:训练指南P246
分析:主要是第二种操作难办,并查集如何支持删除操作?很巧妙的方法:将并查集树上p的影响消除,即在祖先上(sz--, sum -= p),然后为p换上马甲:id[p] = ++pos(可多次),这样id[p]就相当于是新的一个点,那么在Find(x)寻找祖先时要用x的马甲来寻找,即Find (id[x])。
#include <bits/stdc++.h> using namespace std; const int N = 2e5 + 5; int rt[N], sz[N], sum[N], id[N/2]; int n, m; void init() { memset (rt, -1, sizeof (rt)); for (int i=1; i<N; ++i) { sz[i] = 1; sum[i] = i; } for (int i=1; i<=n; ++i) id[i] = i; } int Find(int x) { return rt[x] == -1 ? x : rt[x] = Find (rt[x]); } int main(void) { while (scanf ("%d%d", &n, &m) == 2) { init (); int op, p, q, pos = n; for (int i=1; i<=m; ++i) { scanf ("%d%d", &op, &p); if (op == 3) { int fp = Find (id[p]); printf ("%d %d ", sz[fp], sum[fp]); } else { scanf ("%d", &q); int fp = Find (id[p]), fq = Find (id[q]); if (op == 1) { if (fp != fq) { rt[fp] = fq; sz[fq] += sz[fp]; sum[fq] += sum[fp]; } } else { if (fp != fq) { sz[fp]--; sum[fp] -= p; id[p] = ++pos; //马甲! rt[id[p]] = fq; sz[fq]++; sum[fq] += p; } } } } } return 0; }