该题的难点就在于删除操作, 对于删除操作是有一个通用方法的 。 首先我们要明确,由于并查集是一个树状结构,内部关系复杂,所以如果将其中的一个点直接拆出来,势必会导致树状结构解体。 那么怎么办呢? 我们其实可以不必改变其原有结构,而是用一个id[i]数组表示元素i的编号,每次的删除操作即给元素i分配一个新的编号。因为要求输出集合的元素个数和他们的和,所以我们需要维护这个信息,因为并查集的根结点在路径压缩中是不变的,所以将这两个信息维护在根结点上就行了。
细节参见代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 100000 + 5;
const int maxm = 200000 + 5;
const int INF = 1000000000;
int T,n,a,x,y,m,cnt[maxm],sum[maxm],p[maxm],id[maxn],kase;
void init(int v) {
for(int i=1;i<=v;i++) {
p[i] = i;
sum[i] = i;
cnt[i] = 1;
id[i] = i;
}
}
int findset(int x) { return p[x] == x ? x : p[x] = findset(p[x]); }
int main() {
while(~scanf("%d%d",&n,&m)) {
init(n);
kase = n + 1;
while(m--) {
scanf("%d",&a);
if(a == 1) {
scanf("%d%d",&x,&y);
int xx = id[x], yy = id[y] ;
xx = findset(xx); yy = findset(yy);
if(xx != yy) {
p[xx] = yy;
cnt[yy] += cnt[xx];
sum[yy] += sum[xx];
}
}
else if(a == 2) {
scanf("%d%d",&x,&y);
int xx = id[x], yy = id[y];
xx = findset(xx); yy = findset(yy);
if(xx != yy) {
sum[xx] -= x; cnt[xx]--;
id[x] = kase++;
xx = id[x];
p[xx] = yy;
cnt[yy] += 1; sum[yy] += x;
}
}
else {
scanf("%d",&x);
x = id[x];
x = findset(x);
printf("%d %d\n",cnt[x],sum[x]);
}
}
}
return 0;
}