HDU 2743

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_40924940/article/details/83759077

本题题意

输入 n , m , n个节点 m 个操作

操作分两种 M 之后输入 a b 连接 a b ;

操作 Q 之后输入 c  将 c 从其所属的所有集合中取出;

最终输出 全场剩余集合数量;

本题还是并查集,但是有一个点 就是废除节点,但是我们还不能直接暴力去除掉,因为我们需要他来连接剩下的并查集,所以建立一个虚拟节点,之后再对虚拟节点进行连接,所谓去除 就是把他指向一个新的节点,举个例子 我新开一个数组,用来记录所有并查集的元素,比如 d[i] = i, 之后的 find  unite 操作均对 d[i]  进行 如果进行 “删除操作”,把 d[i] = i+n 不就可以形成删除了吗。

(注意 删除的节点并不是真的删除了,只是单独提出来看做新节点)

以下为AC 代码 

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 2200000;
int pre[maxn];
int vis[maxn];
int d[maxn];
int n,m,num;
void init()
{
    num = n;
    for(int i=0; i<2000000; i++)
    {
            pre[i]=i;
            d[i]=i;
    }
}
int findd(int x)
{
    return  pre[x]==x? x : pre[x] = findd(pre[x]);
}
void unite(int a,int b)
{
    int x=findd(a),y=findd(b);
    if(x!=y)
        pre[y]=x;
}
int main()
{
    int k=1;
    while(scanf("%d%d",&n,&m)&&(n+m))
    {
        init();
        char ch[4];
        while(m--)
        {
            cin>>ch;
            int x,y;
            if(ch[0]=='M')
               cin>>x>>y,unite(d[x],d[y]);
            if(ch[0]=='S')
               cin>>x,d[x]=num++;

        }
        int ans=0;
        memset(vis,0,sizeof(vis));//用来统计集合
        for(int i=0;i<n;i++)
        {
            if(vis[findd(d[i])]==0)
                ans++,vis[findd(d[i])]=1;
        }
       printf("Case #%d: %d\n", k++, ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_40924940/article/details/83759077
hdu