题意:训练指南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\n", 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;
}