题目链接:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3138
题意:n
个点m
个操作,给定三种操作。
1 p q
合并p
和q
所在的集合2 p q
将p
移动到q
所在的集合3 p
输出p
所在集合的元素个数和元素之和
思路:若没有操作2,直接并查集即可。对于操作2中的p
,若p
为叶结点的话,对p
只需直接修改f
函数即可。而绝大多数的情况为p
下面还有节点(p
不一定是根结点),所以对于这种情况,可以考虑新建一个结点来代替p,同时记录一个index[p]
数组,表示当前用来代表p
的结点。
代码:
#include <stdio.h>
const int MAXN = 100000 + 5;
const int MAX2N = 200000 + 5;
int f[MAX2N];
int index[MAXN];
int cnt[MAX2N];
long long sum[MAX2N];
int find(int i) {
return f[i] == i ? i : f[i] = find(f[i]);
}
int main() {
int n, m;
for (int casi = 1; scanf("%d %d", &n, &m) == 2; casi++) {
for (int i = 1; i <= n; i++) {
f[i] = i;
cnt[i] = 1;
sum[i] = i;
index[i] = i;
}
int now = n;
for (int i = 1; i <= m; i++) {
int type, p, q;
scanf("%d", &type);
if (type == 1) {
scanf("%d %d", &p, &q);
int rp = find(index[p]);
int rq = find(index[q]);
if (rp != rq) {
f[rq] = rp;
cnt[rp] += cnt[rq];
sum[rp] += sum[rq];
}
} else if (type == 2) {
scanf("%d %d", &p, &q);
int ip = index[p];
int iq = index[q];
int rp = find(ip);
int rq = find(iq);
now++;
index[p] = now;
f[now] = rq;
cnt[rp]--;
sum[rp] -= p;
cnt[rq]++;
sum[rq] += p;
} else {
scanf("%d", &p);
int rp = find(index[p]);
printf("%d %lld\n", cnt[rp], sum[rp]);
}
}
}
return 0;
}