HDU - 2473 (并查集+设立虚父节点(马甲))

发布时间 2023-06-07 22:16:48作者: kingqiao

涉及到并查集的删除操作,比较复杂,可以利用虚设父节点的方法:

例如 : 有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;
}