HDU 2473 Junk-Mail Filter


题目输入n和m,表示有n封邮件(题目没讲清楚是0~n-1还是1~n,但是看一下Sample,貌似是0~n-1,还有m次操作,最后要求我们输出邮件的类别数。
操作分两种,一种是M操作,后面跟两个操作数A和B,表示编号为A 和编号为B的两封邮件是同一类邮件;另外一种操作是S操作,后面跟一个操作数C,表示将编号为C的邮件从其当前所在类别U分离出来作为一类邮件,即把U分为U-{C}和{C}
很裸的并查集,M操作很容易实现,不多讲,主要讲一下S操作,我想到的有两种思路,一种是直接模拟,时间效率太低,故不讲,另一种思路是加多一封邮件,题目要求我们将邮件C从类别U中分离出来,但对类别U的组成不做要求,所以,我们可以加多一封邮件D,然后,把邮件C 映射到邮件D去,以后对邮件C的操作全部变成对邮件D的操作,这样,就相当于在不严格(不严格是因为U中并没有删除掉邮件C,但这不影响最后的结果)的意义上把邮件C从类别U中分离了出来。
最后再注意一下类别数的统计方法。。

171ms AC

#include <stdio.h>
#include <string.h>
#define MAXN 100000
#define MAXM 1000000

int p[MAXN+MAXM],rank[MAXN+MAXM],map[MAXN];
bool vis[MAXN+MAXM];

void scani(int &num){
    char ch;
	int flag=1;
    while(ch=getchar(),(ch>'9'||ch<'0')&&(ch!='-'));
    if(ch=='-')
        flag=-1,num=0;
    else
        num=ch-'0';
    while(ch=getchar(),(ch<='9'&&ch>='0'))//能吃掉空白字符
        num=num*10+ch-'0';
    num*=flag;
}

int find(int x){
    int r,t,i;
    r=x;
    while(r!=p[r])
        r=p[r];
    i=x;
    while(i!=r){
        t=p[i];
        p[i]=r;
        i=t;
    }
    return r;
}

void merge(int ra,int rb){
    if(rank[ra]==rank[rb]){
        p[rb]=ra;
        rank[ra]++;
    }else{
        if(rank[ra]>rank[rb])
            p[rb]=ra;
        else
            p[ra]=rb;
    }
}

void init(int n){
    int i;
    for(i=0;i<n;i++){
        p[i]=map[i]=i;
		rank[i]=0;
	}
}

int main(){
	int n,m,i,a,b,ra,rb,cnt,cas=0,end;
	char ch;
	while(scani(n),scani(m),n||m){
		init(n);
		end=n;
		while(m--){
			ch=getchar();
			if(ch=='M'){
				scani(a),scani(b);
				ra=find(map[a]),rb=find(map[b]);
				if(ra!=rb)
					merge(ra,rb);
			}else{
				scani(a);
				map[a]=end;
				p[end]=end;
				rank[end]=0;
				end++;
			}
		}
		cnt=0;
		memset(vis,0,end*sizeof(bool));
		for(i=0;i<n;i++){
			ra=find(map[i]);
			if(!vis[ra]){
				cnt++;
				vis[ra]=1;
			}
		}
		printf("Case #%d: %d\n",++cas,cnt);
	}
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值