題目鏈接: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;
}