HDU - 2473 (并查集+设立虚父节点(马甲))
涉及到并查集的删除操作,比较复杂,可以利用虚设父节点的方法:
例如 : 有n个节点,进行m次操作.首先将0 ~ n-1的节点的父节点设置为i + n,n ~ 2n+1的节点的父节点设置为本身,有m次操作,所以要用到m个虚节点,例如0,1,2,3,4,5的父节点为7,8,9,10,11,把他们插入2的集合,所以他们的根节点都为8,当把2从集合中移除时就可以把2的根节点设置为没有用到的数12,所以此时0,1,3,4,5的根节点为8,2的根节点为12,形成了两个独立的集合
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+10, M = 1e6+10;
int fa[N+N+M],n,m,id;
bool vis[N+N+M];
int find(int x){
if(fa[x]==x) return x;
return fa[x] = find(fa[x]);
}
void joint(int x,int y){
x = find(x), y = find(y);
if(x!=y) fa[x] = y;
}
int main(){
while(scanf("%d %d",&n,&m)&&(n+m)){
memset(vis,0,sizeof vis);
for(int i=0;i<n;i++) fa[i]=i+n;
for(int i=n;i<n+n+m;i++) fa[i]=i;
int temp = n+n;
while(m--){
char flag;
int x,y;
scanf("%s",&flag);
if(flag=='M'){
scanf("%d %d",&x,&y);
joint(x,y);
}
else{
scanf("%d",&x);
fa[x] = temp++;
}
}
int ans = 0;
for(int i=0;i<n;i++){
if(!vis[find(i)]){
ans++;
vis[find(i)] = 1;
}
}
printf("Case #%d: %d\n",++id,ans);
}
return 0;
}