*hdu2473 (并查集的删除)

题意:给定n个点,刚进行两种操作,r如果为M将两个点合并,如果为S将一个得到点与前面已经合并的堆中孤立,问最后点有几堆;
分析:删除一个点,只是将该点独立起来,或者说将该点从所在集合中脱离,而所在集合的结构不变,若真的将该点从集合中删去,会带来很多不必要的麻烦,所以,可以反而添加一个虚拟的点代替独立出来的点,这样,用一个数组hash将每一个点都映射到一个虚拟的点上,之后在虚拟的点(hash)上面操作即可。当要独立一个点时,只需将该点映射到另一个原先不存在的点即可。
之后,统计集合个数有俩种方法,一个是根据集合含有的元素的个数,另一个则是统计根节点的个数。
代码:

#include<stdio.h>
#define M 1000005
int a[M],hash[M],ret[M];//hash为数组a的映射数组,ret记录每个堆中元素和;
int find(int tt)
{
    if(tt!=a[tt])
        a[tt]=find(a[tt]);
    return a[tt];
}
void sort(int x,int y)
{
    int zx=find(x);
    int zy=find(y);
    if(zx==zy)
        return;
    if(ret[zx]<ret[zy]) //将一个堆的元素和集中在根节点上,堆中其他点则可以ret为0;
    {
        a[zx]=zy;
        ret[zy]+=ret[zx];
        ret[zx]=0;
    }
    else
    {
        a[zy]=zx;
        ret[zx]+=ret[zy];
        ret[zy]=0;
    }
}
int main()
{
    int n,m,ss=0;
    while(~scanf("%d%d",&n,&m),n||m)
    {
        char c;
        int x,y;
        int i,j,k;
        for(i=0;i<M;i++)
        {
            a[i]=i;
            hash[i]=i;
            ret[i]=1;
        }
        while(m--)
        {
            getchar();

            scanf("%c",&c);
            if(c=='M')
            {
                scanf("%d%d",&x,&y);
                sort(hash[x],hash[y]);//应该引用x,y对应的映射值;
            }
            else
            {
                scanf("%d",&x);
                ret[find(hash[x])]--;//将x所在的堆得元素和减一;
                hash[x]=n++; //将x映射到n;
            }
        }
        int ans=0;
        for(i=0;i<n;i++)
            if(ret[i]>0)//判断有几个堆;
                ans++;
            printf("Case #%d: %d\n",++ss,ans);

    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值