HDU 2473 Junk-Mail Filter

来源:互联网 发布:arp a mac好多相同 编辑:程序博客网 时间:2024/06/05 07:59


题目输入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 1000000int 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;}



原创粉丝点击