hdu 2473 (并查集删点)

Junk-Mail Filter

 HDU - 2473 

题目大意:每次给出两个点,代表这两个点在同一个集合里,然后s操作是将该点从它原属的集合中去除,自己成为独立的一个集合。问最后有几个不同的集合。

解题思路:并查集,对于每次删除操作我们并不改变原来的关系,而是给当前要删除的节点重新找一个假的父亲(需要用另一个数组保存下来)这样就相当于不改变原来关系的同时将该点从图中拿了出来。

例如下图。

如果我们想把2节点从图中删除,并且保留图中其他点之间的关系,我们并不能去改变这个图。我们只需要把b[2]该成另外一个值,

这个时候我们再去查询2的时候我们就相当于查询的b[2]==6。

如果此时要合并2-1

就相当于合并b[2]-1即6-1

这个时候2点相当于又回到了集合里。

#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
#include<set>
#include<algorithm>
#include<cstring>
using namespace std;
#define rep(i,j,k) for(int i=j;i<=k;i++)
#define sca(x) scanf("%d",&x)
#define per(i,j,k) for(int i=j;i>=k;i--)
#define inf 0x3f3f3f3f
#define LL long long
#define N 1000005
#define inf 0x3f3f3f3f
const LL mod = 998244353;
set<int>ss;
int f[N],a[N];
int F(int x)
{
    return f[x]==x?x:f[x]=F(f[x]);
}

void U(int x,int y)
{
    int f1=F(x);
    int f2=F(y);
    if(f1!=f2)
        f[f1]=f2;
}
int main()
{
    int n,m;
    int cas=1;
    while(~scanf("%d%d",&n,&m))
    {
        if(n==0&&m==0)break;
        rep(i,0,1000000)f[i]=i;
        rep(i,0,100000)a[i]=i;
        char s[3];
        int x,y;
        int now=n+1;
        rep(i,1,m)
        {
            scanf("%s",s);
            if(s[0]=='M')
            {
                scanf("%d%d",&x,&y);
                U(a[x],a[y]);
            }
            else
            {
                scanf("%d",&x);
                a[x]=now++;
            }
        }
        rep(i,0,n-1)
        {
            ss.insert(F(a[i]));
        }
        printf("Case #%d: %d\n",cas++,ss.size());
        ss.clear();
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_40894017/article/details/82805920