hdu2473 删点并查集

题意:典型并查集的操作 合并两个点 从指定的集合中删去一个点 询问当前集合的个数


解法:第一道可删点并查集,做法很明显就是建立虚拟节点 由于在集合的合并操作中所有点都会因为路经压缩而链接到根节点上,而根节点是我们设立的虚拟节点 那么我们可以轻易地修改当前节点的父亲来导致当前点的孤立,这样我们就完成了删点 


注意点:这个并查集写的时候还要维护每个集合所有的点数,这样我们就可以进行特判

如果点的个数是1或者这个点还没有连接过集合 那么我们在删除的时候就不需要考虑它了


这题让我想起了早前校赛的时候没有写掉的并查集 然后导致了浙大的月赛也没做出来 真是惭愧 

看来补题还债是必要的 平时做的时候尽量往透彻知识点的方向努力

#include
#include
#include
using namespace std;
#define maxn 2222222
int f[maxn],cnt[maxn];
int find(int x){
    return x==f[x]?x:f[x]=find(f[x]);
}
char op[5];
int main(){
    int n,m,cas=0,a,b,tot,x,y,ans;
    while(~scanf("%d%d",&n,&m)){
        if(!n&&!m)break;
        cas++;
        for(int i=1;i<=n;++i)f[i]=0;
        f[0]=0;cnt[0]=1;
        ans=tot=n;
        while(m--){
            scanf("%s",op);
            if(*op=='M'){
                scanf("%d%d",&x,&y);
                ++x;++y;
                a=find(x);b=find(y);
                if(a==0||b==0||a!=b){
                    ans--;tot++;
                    f[tot]=tot;cnt[tot]=0;
                    if(a){
                        f[a]=tot;cnt[tot]+=cnt[a];
                        cnt[a]=0;
                    }
                    else{
                        f[x]=tot;
                        cnt[tot]++;
                    }
                    if(b){
                        f[b]=tot;cnt[tot]+=cnt[b];
                        cnt[b]=0;
                    }
                    else{
                        f[y]=tot;cnt[tot]++;
                    }
                }
            }
            else{
                scanf("%d",&x);++x;
                y=find(x);
                if(y==0||cnt[y]==1)continue;
                f[x]=0;cnt[y]--;
                ans++;
            }
        }
        printf("Case #%d: %d\n",cas,ans);
    }
    return 0;
}


你可能感兴趣的:(并查集)