题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=2473
A={1,2,3,4}删除1后A={2,3,4};
注意:
(1)在删除节点a时,不能直接将fa[a]=a。首先,如果a的根为自己,那么更改无效;其次,如果b节点是通过a节点才能找到自己的父节点,在改变fa[a]的值后,b节点的父节点无法找到。
(2)wa了好多次,错在n,m值的判断。。。。。能不犯这么脑残的错误么if(n==0&&m==0) break;
思路:
删除a节点是不改变之前a与其父节点的关系,而是给a一个新的id,记做id[a],在之后fa[id[a]]表示a的新的父节点。
<span style="font-family:SimSun;">#include<cstdio>
#include<cstring>
using namespace std;
const int num=1100011;
int n,m,p[num],id[num],fa[num],r[num],d;
void init()
{
int i;
for(i=0;i<n;i++)
{
fa[i]=i;
id[i]=i;
r[i]=1;
}
d=n;
}
int find(int a)
{
if(fa[a]==a)
return a;
return find(fa[a]);
}
void uni(int a,int b)
{
int ra,rb;
ra=find(a);
rb=find(b);
if(ra!=rb)
{
if(r[ra]>r[rb])
{
fa[rb]=ra;
r[ra]+=r[rb];
}
else
{
fa[ra]=rb;
r[rb]+=r[ra];
}
}
}
void del(int a)
{
fa[d]=d;
id[a]=d++;
}
int main()
{
int i,a,b,k=0,ans,temp;
char s[4];
//freopen("in.txt","r",stdin);
while(scanf("%d%d",&n,&m)!=EOF)
{
if(n==0&&m==0)
break;
init();
k++;
while(m--)
{
scanf("%s",s);
if(s[0]=='M')
{
scanf("%d%d",&a,&b);
uni(id[a],id[b]);
}
else
{
scanf("%d",&a);
del(a);
}
}
memset(p,0,sizeof(p));
ans=0;
for(i=0;i<n;i++)
{
temp=find(id[i]);
if(p[temp]==0)
{
ans++;
p[temp]=1;
}
}
printf("Case #%d: %d\n",k,ans);
}
return 0;
}</span>