4018

来源:互联网 发布:超滤膜端口连接 编辑:程序博客网 时间:2024/06/05 09:02

4018

Problem R

Time Limit : 15000/8000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other)
Total Submission(s) : 4   Accepted Submission(s) : 2
Problem Description
Recognizing junk mails is a tough task. The method used here consists of two steps:<br>1) Extract the common characteristics from the incoming email.<br>2) Use a filter matching the set of common characteristics extracted to determine whether the email is a spam.<br><br>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:<br><br>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<br>relationships (other than the one between X and Y) need to be created if they are not present at the moment.<br><br>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.<br><br>Initially no relationships exist between any pair of the junk emails, so the number of distinct characteristics at that time is N.<br>Please help us keep track of any necessary information to solve our problem.
 

Input
There are multiple test cases in the input file.<br>Each test case starts with two integers, N and M (1 ≤ N ≤ 10<sup>5</sup> , 1 ≤ M ≤ 10<sup>6</sup>), the number of email samples and the number of operations. M lines follow, each line is one of the two formats described above.<br>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 6M 0 1M 1 2M 1 3S 1M 1 2S 33 1M 1 20 0
 

Sample Output
Case #1: 3Case #2: 2

题意:有N 封邮,编号 0 -> N-1,  然后有两种操作,  M : 合并操作, 2 种邮件合并为一种;S  : 分离操作, 将一封邮件独立出去单独占一个集合,


最后题目要求统计集合的个数.   从这里可以很容易的看出这是一个并查集的题目, 不过按朴素方法来做的一般都会TLE.

思路:因为并查集是树形结构,所以无法简单的把一个节点从一棵树中删去并维护原来的信息。那这里用到的思想就是还是保持原来的树的结构不变,只是把被删掉的那个点设为虚点,并新建一个点,把原来的点映射到这个新点上,代表以后的操作都是对这个新点进行操作。这样空间开销虽然大,但还是可以解决问题的。


AC代码:

#include <iostream>  
#include <cstring>  
#include <cstdio>  
#include <string>  
#include <algorithm>  
#include <map>  
#include <vector>  
#include<queue>  
#include<set>  
using namespace std;  
typedef long long LL;  
typedef pair<int,int> P;  
const int maxn = 2000000 + 5;  
const int INF = 1000000000;  
  
int cnt;  
int fa[maxn],id[maxn];  
  
int Find(int x){return fa[x]==x?fa[x]:fa[x]=Find(fa[x]);}  
set<int> S;  
  
int main(){  
    int n,m;  
    int kase = 0;  
    while(scanf("%d%d",&n,&m)){  
        if(n == 0 && m == 0) break;  
        kase++;  
        cnt = n;  
        for(int i = 0;i < maxn;i++) fa[i] = i;  
        for(int i = 0;i < n;i++) id[i] = i;  
        while(m--){  
            char s[5];  
            int a,b;  
            scanf("%s",s);  
            if(s[0] == 'M'){  
                scanf("%d%d",&a,&b);  
                int X = Find(id[a]);  
                int Y = Find(id[b]);  
                if(X != Y) fa[X] = Y;  
            }  
            else{  
                scanf("%d",&a);  
                id[a] = cnt++;  
            }  
        }  
        S.clear();  
        for(int i = 0;i < n;i++){  
            S.insert(Find(id[i]));  
        }  
        printf("Case #%d: %d\n",kase,S.size());  
    }  
    return 0;  
}  

0 0
原创粉丝点击