题意:初始有N个集合,分别为 1 ,2 ,3 .....n。有三种操件
1 p q 合并元素p和q的集合
2 p q 把p元素移到q集合中
3 p 输出p元素集合的个数及全部元素的和。
1、3操作比较简单,关键是2操作,并查集不能删除元素,但是我们要求的结果其实和要删除的元素没有关系,所以我们考虑用一个新的节点代替要删除的元素,用nid表示要删除的元素的新的id,这样我们就可以实现2操作了
代码如下:
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
#include<stack>
#include<string>
#include<map>
#include<set>
using namespace std;
#define LL long long
const int maxn = 200000 + 5;
const int INF = 1000000000;
//freopen("input.txt", "r", stdin);
int num[maxn], sumu[maxn], pa[maxn], nid[maxn];
void init(int n) {
for(int i = 1; i <= n; i++) { pa[i] = i; num[i] = 1; sumu[i] = i; nid[i] = 0;}
}
int find(int x) {
if(x != pa[x]) return pa[x] = find(pa[x]);
return x;
}
int main() {
int n, m;
while(scanf("%d%d", &n, &m) != EOF) {
init(n);
int cnt = n + 1;
for(int i = 1; i <= m; i++) {
int cmd; scanf("%d", &cmd);
switch(cmd) {
case 1: {
int p, q; scanf("%d%d", &p, &q);
int u = nid[p] == 0? find(p) : find(nid[p]);
int v = nid[q] == 0? find(q) : find(nid[q]);
if(u != v) {
pa[u] = v;
sumu[v] += sumu[u];
num[v] += num[u];
}
break;
}
case 2: {
int p, q; scanf("%d%d", &p, &q);
int u = nid[p] == 0? find(p) : find(nid[p]);
int v = nid[q] == 0? find(q) : find(nid[q]);
if(u != v) {
nid[p] = cnt++;
pa[nid[p]] = v;
sumu[v] += p; sumu[u] -= p;
num[v]++; num[u]--;
}
break;
}
case 3: {
int p, ans1, ans2; scanf("%d", &p);
if(!nid[p]) ans1 = num[find(p)], ans2 = sumu[find(p)];
else ans1 = num[find(nid[p])], ans2 = sumu[find(nid[p])];
printf("%d %d\n", ans1, ans2);
break;
}
}
}
}
return 0;
}