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 
#include 
#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



你可能感兴趣的:(HDU 2473 Junk-Mail Filter)