题意:给你一些相连的两点(带传递,显然是集合),并会对某些点进行删除操作,最终问你集合的数目
解析:删除某个节点时,不是将与此节点所有关系都删除,只是将此节点隐藏,
别的结点的父节点还可以是此节点,用rep【】表示修改后的结点,例如,
原来结点是1、2、3,删除2结点,最后的1、2、3结点经rep【1、2、3】后
存的虚结点为1、4、3;即删除的结点用rep【i】=n++;然后看最终合并后的
每个结点的父节点,如果父节点相同,则在同一集合内,可以用vis【】来看有多少
不同的父节点,即多少不同的集合(注意路径压缩下)
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=5130009;
int vis[maxn];
int set[maxn];
int rep[maxn];
int n,m;
int find(int x)
{
int r=x;
while(r!=set[r])
r=set[r];
int i=x;
while(i!=r)
{
int j=set[i];
set[i]=r;
i=j;
}
return r;
}
void merge(int x,int y)
{
int fx=find(x);
int fy=find(y);
if(fx!=fy)
set[fx]=fy;
}
int main()
{
int cnt=0;
while(scanf("%d%d",&n,&m)!=EOF&&(n+m))
{
memset(vis,0,sizeof(vis));
for(int i=0;i<n;i++)
{
rep[i]=i;
set[i]=i;
}
cnt++;
int d=n;
char st[23];
int x,y;
for(int i=0;i<m;i++)
{
scanf("%s",st);
if(st[0]=='M')
{
scanf("%d%d",&x,&y);
merge(rep[x],rep[y]);
}
else
{
scanf("%d",&x);
rep[x]=d;
set[d]=d;
d++;
}
}
int count=0;
for(int i=0;i<n;i++)
{
if(vis[find(rep[i])]==0)
{
vis[find(rep[i])]=1;
count++;
}
}
printf("Case #%d: %d\n",cnt,count);
}
return 0;
}