1. 程式人生 > >HDU 2473 Junk-Mail Filter 【並查集刪除】

HDU 2473 Junk-Mail Filter 【並查集刪除】

limit nes chmod from src desc command rdquo sid

Junk-Mail Filter

Time Limit: 15000/8000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 8640 Accepted Submission(s): 2735

Problem Description

Recognizing junk mails is a tough task. The method used here consists of two steps:
1) Extract the common characteristics from the incoming email.


2) Use a filter matching the set of common characteristics extracted to determine whether the email is a spam.

We want to extract the set of common characteristics from the N sample junk emails available at the moment, and thus having a handy data-analyzing tool would be helpful. The tool should support the following kinds of operations:


a) “M X Y”, meaning that we think that the characteristics of spam X and Y are the same. Note that the relationship defined here is transitive, so
relationships (other than the one between X and Y) need to be created if they are not present at the moment.

b) “S X”, meaning that we think spam X had been misidentified. Your tool should remove all relationships that spam X has when this command is received; after that, spam X will become an isolated node in the relationship graph.


Initially no relationships exist between any pair of the junk emails, so the number of distinct characteristics at that time is N.
Please help us keep track of any necessary information to solve our problem.

Input

There are multiple test cases in the input file.
Each test case starts with two integers, N and M (1 ≤ N ≤ 105 , 1 ≤ M ≤ 106), the number of email samples and the number of operations. M lines follow, each line is one of the two formats described above.
Two successive test cases are separated by a blank line. A case with N = 0 and M = 0 indicates the end of the input file, and should not be processed by your program.

Output

For each test case, please print a single integer, the number of distinct common characteristics, to the console. Follow the format as indicated in the sample below.

Sample Input

5 6

M 0 1

M 1 2

M 1 3

S 1

M 1 2

S 3

3 1

M 1 2

0 0

Sample Output

Case #1: 3

Case #2: 2

Source

2008 Asia Regional Hangzhou

【分析】:由於並查集是一種樹結構,無法在樹中刪除一個點後還讓樹繼續保持著之前的樣子,所以我們刪除采取的操作是使用映射,一開始所有點的映射都是自己,然後刪除操作就是把這個點映射到另一個不存在的點上,這樣原來的點還在原來的集合中,用來保持著原先集合的各種屬性,之後的所有對這個點的操作都是對它映射的點的操作。與一般的並查集不同的是,找父親的操作,找的不是這個點本身的父親,而是所有點的映射的父親。每一個點都設立一個虛擬父親比如1,2,3的父親分別是4,5,6,現在合並1,2,3都在一個集合,那他們的父親都是4,現在刪除1,那就給1重新申請一個節點7。現在2,3的父親是4,1的父親是7,刪除成功。

//這是關鍵, 雖然空間的消耗比較大, 但是節省了大量時間, 這樣處理的目的是將0 -> N-1 的 節點處理成葉子節點,這樣在對這些節點做 S 操作的時候就不會影響到其他的節點, 而 find 操作是帶路徑壓縮的, 所以就保證了我們所有要處理的節點一直是葉子節點 !!!

     for(i=0;i<n;i++)       bin[i]=i+n; //虛擬父節點
    for(i=n;i<=n+n+m;i++)  bin[i]=i //最多可能刪除m個節點

技術分享

技術分享

技術分享

技術分享

技術分享

【代碼】:

技術分享
#include<stdio.h>
#include<string.h>
using namespace std;
int vis[1200000];
int f[1200000];
int find(int a)
{
    int r=a;
    while(f[r]!=r)
    r=f[r];
    int i=a;
    int j;
    while(i!=r)
    {
        j=f[i];
        f[i]=r;
        i=j;
    }
    return r;
}
void merge(int a,int b)
{
    int A,B;
    A=find(a);
    B=find(b);
    if(A!=B)
    f[B]=A;
}
int main()
{
    int n,m;
    int kase=0;
    while(~scanf("%d%d",&n,&m))
    {
        if(n==0&&m==0)break;
        int cont=n*2;
        for(int i=0;i<n;i++)
        {
            f[i]=i+n;
        }
        for(int i=n;i<2*n+m+1;i++)
        {
            f[i]=i;
        }
        for(int i=0;i<m;i++)
        {
            char op[5];
            scanf("%s",op);
            if(op[0]==M)
            {
                int x,y;
                scanf("%d%d",&x,&y);
                merge(x,y);
            }
            if(op[0]==S)
            {
                int x;
                scanf("%d",&x);
                f[x]=cont++;
            }
        }
        int output=0;
        memset(vis,0,sizeof(vis));
        for(int i=0;i<n;i++)
        {
            int tmp=find(i);
            if(vis[tmp]==0)
            {
                vis[tmp]=1;
                output++;
            }
        }
        printf("Case #%d: %d\n",++kase,output);
    }
}
View Code

HDU 2473 Junk-Mail Filter 【並查集刪除】