注意:操作 \(3\) 并没有要求查询后从其所在集合里删除该元素。
因为有操作 \(2\),我们给每个点建一个虚点,用来表示集合来维护答案。普通的点初始就认对应集合为爸爸,然后普通的点就可以随便移动了。
#include <cstdio>
const int N = 1e5 + 5;
int n, m, f[N], cnt[N];
long long ans[N];
int read() {
int x = 0, f = 1; char s;
while((s = getchar()) < ‘0‘ || s > ‘9‘) if(s == ‘-‘) f = -1;
while(s >= ‘0‘ && s <= ‘9‘) {x = (x << 1) + (x << 3) + (s ^ 48); s = getchar();}
return x * f;
}
int Find(const int x) {return x == f[x] ? x : f[x] = Find(f[x]);}
void init() {for(int i = 1; i <= n; ++ i) f[i] = n + i, f[n + i] = n + i, cnt[n + i] = 1, ans[n + i] = i;}
int main() {
int op, x, y, u, v;
while(~ scanf("%d %d", &n, &m)) {
init();
while(m --) {
op = read();
if(op == 1) {
x = read(), y = read();
u = Find(x), v = Find(y);
if(u == v) continue;
ans[v] += ans[u]; cnt[v] += cnt[u]; f[u] = v;
}
else if(op == 2) {
x = read(), y = read();
u = Find(x), v = Find(y);
f[x] = v;
-- cnt[u]; ++ cnt[v];
ans[u] -= x, ans[v] += x;
}
else {
x = Find(read());
printf("%d %lld\n", cnt[x], ans[x]);
}
}
}
return 0;
}
原文:https://www.cnblogs.com/AWhiteWall/p/12926295.html