Junk-Mail Filter HDU - 2473

原题链接

考察:并查集

看了大佬的代码后才懂.本蒟蒻属实好菜..

正确思路:

       考点就是并查集删除点的操作.如果每个点的父亲赋原值,那么findf函数后修改某一非叶子结点,后面的结点也会被修改为修改后的值.因此此法无效

        正确做法是设置虚父结点.i的父亲是i+n,但初始化的时候和一般并查集有点不一样.在草稿纸上画图更容易理解,设置虚父结点后,1~n都变成了叶子结点,所以修改不会影响其他结点

易错:

        如果写成++idx,初始化就要到<=n*2+m

2021.3.7 二刷,并查集直接的将p[x] = y,本质是将以x为根的树全部移到另一个根上,这里之所以设置虚父结点,本质利用并查集的自然的删除操作.

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <set>
 4 using namespace std;
 5 const int N = 1e5+10,M = 1e6+10;
 6 int n,m,p[N*2+M],idx;
 7 set<int> s;
 8 int findf(int x)
 9 {
10     if(x!=p[x]) p[x] = findf(p[x]);
11     return p[x];
12 }
13 void del(int x)
14 {
15     p[x] = idx++;
16 }
17 void merge(int x,int y)
18 {
19     int px = findf(x),py = findf(y);
20     p[px] = py;
21 }
22 int main()
23 {
24     int kcase = 0;
25     while(scanf("%d%d",&n,&m)!=EOF&&n)
26     {
27         idx = n*2; int cnt =0;
28         s.clear();
29         for(int i=0;i<n;i++) p[i] = i+n;
30         for(int i=n;i<n*2+m;i++) p[i] = i;
31         while(m--){
32             char op[2];
33             scanf("%s",op);
34             if(op[0]=='M')
35             {
36                 int x,y; scanf("%d%d",&x,&y);
37                 merge(x,y);
38             }else{
39                 int x; scanf("%d",&x);
40                 del(x);
41             }
42         }
43         for(int i=0;i<n;i++)
44         {
45             int x = findf(i);
46             if(!s.count(x)) cnt++;
47             s.insert(x);
48         } 
49         printf("Case #%d: %d\n",++kcase,cnt);
50     }
51     return 0;
52 } 

 

posted @ 2021-01-15 00:45  acmloser  阅读(74)  评论(0编辑  收藏  举报