思路参考的别人的题解~
在删除结点的时候要注意这样的问题: 并查集的结构是一棵树,当把某一个结点删去(将其父结点置为自己)时,它的子结点的根就会丢失.因此,在删除某结点的时候,要确定它的所有子结点都已经并到根上了.
解决方法: 为每一个结点加一个虚根,这样每个结点都是叶子结点.插入结点时,把它们都并到虚根的集合中.删除结点时,只要把它的父结点置为一个无用的虚根。
。。。下面贴自己的代码
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<set>
using namespace std;
const int maxn = 100005;
const int maxm = 1000005;
const int N = 2*maxn + maxm;
int n,m;
int par[N],rnk[N];
set<int> ans;
void init_union(){
ans.clear();
memset(par,-1,sizeof(par));
memset(rnk,0,sizeof(rnk));
for(int i=0;i<n;i++){
par[i] = i + n;
}
}
int find(int x){
while(par[x] >= 0) x = par[x];
return x;
}
void unite(int x,int y){
x = find(x);y = find(y);
if(x == y) return;
if(rnk[x] < rnk[y]){
par[x] = y;
}else{
par[y] = x;
if(rnk[x] == rnk[y]) rnk[x]++;
}
}
int main(){
int cas = 0;
while(~scanf("%d%d",&n,&m)){
if(n == 0 && m == 0) break;
init_union();
char op[5];int a,b;
int tmp = 2*n;
while(m--){
scanf("%s",op);
if(op[0] == 'M'){
scanf("%d%d",&a,&b);
unite(a,b);
}else{
scanf("%d",&a);
par[a] = tmp++;
}
}
for(int i=0;i<n;i++){
ans.insert(find(i));
}
printf("Case #%d: %d\n",++cas,ans.size());
}
return 0;
}