来个杭电的题 ---并查集 HDU 2473 Junk-Mail Filter

http://acm.hdu.edu.cn/showproblem.php?pid=2473

写挫了,wa了一次

题意简单来说,就是给你n个点,m条命令,M a b表示a b在同一个集合,S a表示从a的集合把a拿走,当做一个新的集合。问最后有几个集合。

这样的题意已经抽象好了,提到集合,必然是并查集,没什么好说的,但是我们的并查集都是添加点,没有删除的,今天遇到这么一个题,需要把并查集修改一下。

想法是:

比如有4个点0 1 2 3,那么我加4个点4 5 6 7,1->4 ,2->5 , 3->6  ,4->7,如果1和2连接,就用1的祖先指向2的祖先,要删除一个点的时候,比如3,直接fa【3】=某个数,某个数是多少呢,最坏的情况是m条命令都是删除,那么我再加m个点,比如m=3,那么就加上8 9 10这三个点,3->8,这样做,所有的(0,n-1)中的点都是叶子,不会因为某个点删除了,从而指向它的点跟着过去,比如2->3,不会有删除3同时把2带走的效果,因为所有的祖先都是不在(0,n-1)的,所有的节点的父亲都不在(0,n-1)里面,所以你可以随便删除,都不会影响到其他的点。

最后如何统计集合数?很简单,建一个set,把(0,n-1)所有的祖先够扔到set里,最后set的size就是集合的数量。

提一句,找父亲结点的时候用到路径压缩。见代码:

#include "iostream"
#include "cstdio"
#include "cstring"
#include "cmath"
#include "stdlib.h"
#include "algorithm"
#include "set"
using namespace std;


int fa[1200010];
int n,m,a,b,cnt,cas=1;
char op[10];
set<int> st;


int getfa(int x)
{
    if(fa[x]==x)
        return x;
    fa[x]=getfa(fa[x]);
    return fa[x];
}
int main()
{
    //freopen("in.txt","r",stdin);
    while(scanf("%d %d",&n,&m))
    {
        if((m|n)==0)
            break;
        cnt=2*n;
        for(int i=0; i<n; i++)
            fa[i]=i+n;
        for(int i=n; i<2*n+m; i++)
            fa[i]=i;
        for(int i=0; i<m; i++)
        {
            scanf("%s",op);
            if(op[0]=='M')
            {
                scanf("%d %d",&a,&b);
                fa[getfa(a)]=getfa(b);
            }
            else
            {
                scanf("%d",&a);
                fa[a]=cnt++;
            }
        }
        st.clear();
        for(int i=0; i<n; i++)
            st.insert(getfa(i));
        printf("Case #%d: %d\n",cas++,st.size());
    }
    return 0;
}







水平有限,众神轻喷。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值