Topic Link:
http://acm.hdu.edu.cn/showproblem.php?pid=2473
Original title:
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" N sample junk emails available at the moment, and thus G A handy data-analyzing tool would be helpful. The tool should support the following kinds of operations:
A) "M X y", meaning that we do, and the characteristics of spam X and Y are the same. Note that the relationship defined this is transitive
Relationships (the other than, the one between X and Y) need to is created if they are not present at the moment.
This column more highlights: http://www.bianceng.cn/Programming/sjjg/
b) "S X", meaning that we spam x had been misidentified. Your tool should remove all relationships which spam X has when this command is received; After that, spam X would become a isolated node in the relationship graph.
Initially no relationships exist between any pair of the junk emails, so the number of distinct characteristics in that Ti Me is N.
Please help us keep track the 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 O F Operations. M lines follow, which 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" input file, and should not is processed by your.
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
Analysis and Summary:
There are n messages, then two operations, and if it is M x y, it means that x and Y are the same message. If it is S X, then the judgment of X is wrong, X is the set that does not belong to X, and the x is separated so that x becomes a separate one.
It's obviously done with a collection of checks. One of the things that began to confuse me was to assume the following
M 0 2
M 1 2
S 2
So follow and check the set, 0 points 2, 1 points 2, that's
0-->2
1-->2,
Then delete 2, I think the title is that all of the relationship with the 2 to delete, then the two relationships will be removed, and become independent of the 3.
But my understanding is wrong. Combined is a set {0,1,2}, if you delete 2, {0,1} is still a collection.
After understanding the idea, we know that it is easy to construct the set by using and searching the set, but it is not easy to delete one from the collection. Through this problem, I learned the so-called set up a virtual parent node method.
The key process is to assume that you want to delete x points, so instead of really deleting x points, instead of using a map (here with an array of majia[n]), turn X into a new point, majia[x] = NewNode. So, the original set is still the same, just missing an x point.
Code:
#include <cstdio> #include <cstring> #define N 1100000 int f[n],rank[n],majia[n],flag[n],id,n,m;
inline void init () {for (int i=0; i<n; ++i) f[i]=majia[i]=i;
memset (rank, 0, sizeof (rank));
Id=n;
int find (int x) {int i, j=x;
while (J!=f[j]) j=f[j];
while (x!=j) {i=f[x];f[x]=j;x=i}
Return J;
} void Union (int x,int y) {int a=find (x), B=find (y);
if (a==b) return;
if (rank[a]>rank[b]) f[b]=a;
else{if (rank[a]==rank[b]) ++rank[b];
F[a]=b;
} void Delete (int x) {f[id]=id;
majia[x]=id++;
int main () {char cmd[3];
int A,b,cas=1;
while (~SCANF ("%d%d", &n,&m) &&n+m) {init ();
for (int i=0; i<m; ++i) {scanf ("%s", cmd);
if (cmd[0]== ' M ') {scanf ("%d%d", &a,&b);
Union (Majia[a],majia[b]); } else{scanf ("%d", &a);
Delete (a);
} memset (flag, 0, sizeof (flag));
int ans=0;
for (int i=0; i<n; ++i) {a=find (majia[i]);
if (!flag[a]) {++ans;
Flag[a]=1;
} printf ("Case #%d:%d\n", cas++, ans);
return 0; }