原来是这样啊、、、、、、、、、、、、、、、、、、!
题意:给你一些相连的两点(带传递,显然是集合),并会对某些点进行删除操作,最终问你集合的数目
显然是并查集,可是并查集,怎么去删除一个点呢??我想想想……晕了!不知道怎么删除。。最后……
思想:删除操作就是用其他(用不到的)的点代替该点,JUST AND ONLY SO!!原集合中的该点JUST
作为其它某些点的桥梁,通向根节点的桥梁,也就是ancestor[x]不变!若再删除,再用其它点代替,那么
曾经的替代品也成了桥梁!!
代码:
View Code
#include <stdio.h>
#include <string.h>
#define N 100002
#define M 1000002
//-----Union_Find_Set------------------
int ancestor[N+M];
int replace[N],ind;
void Sinit(int n)
{
int i;
for(i=0;i<n;i++)
{
ancestor[i]=i;
replace[i]=i;
}
ind=n;
}
int Sfind(int x)
{
if(x!=ancestor[x])
ancestor[x]=Sfind(ancestor[x]);
return ancestor[x];
}
void Sunion(int x,int y)
{
int ancex=Sfind(x),ancey=Sfind(y);
ancestor[ancex]=ancey;
}
void Sdelete(int x)
{
replace[x]=ind;
ancestor[ind]=ind;
++ind;
}
//--------------------------------------------
bool flag[N+M];
int main()
{
int n,m;
int i,x,y,ans,ance,cas=0;
char c[2];
// freopen("input.txt","r",stdin);
while(scanf("%d %d",&n,&m) && n)
{
Sinit(n);
for(i=0;i<m;i++)
{
scanf("%s",c);
if(c[0]=='M')
{
scanf("%d %d",&x,&y);
Sunion(replace[x],replace[y]);
}
else
{
scanf("%d",&x);
Sdelete(x);
}
}
memset(flag,false,sizeof(flag)); ans=0;
for(i=0;i<n;i++)
{
ance=Sfind(replace[i]);
if(!flag[ance])
{
++ans;
flag[ance]=true;
}
}
printf("Case #%d: %d\n",++cas,ans);
}
return 0;
}
额,这题不错,让我知道了并查集的另一个操作,哈哈,有水平!!