并查集专题2

hdu 1829 A Bug's Life

http://acm.hdu.edu.cn/showproblem.php?pid=1829

解题思路:这个题目跟其他的不太一样,给出的不是同类而是异类,其实是差不多的。

增加一个sex[i]表示i的异类,那么就是有两个集合,输入一组数据的时候判断一下两个是不是在同一个集合里,如果是那么输出Suspicious bugs found!

一直没有输出No suspicious bugs found!

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #define maxlen 2010
 5 using namespace std;
 6 int father[maxlen];
 7 int sex[maxlen];
 8 int n,m;
 9 void init()
10 {
11     for(int i=0; i<=n; ++i)
12     {
13         father[i]=i;
14         sex[i]=0;
15     }
16 }
17 int Find(int x)
18 {
19     return father[x]==x?x:father[x]=Find(father[x]);
20 }
21 void Union(int x ,int y)
22 {
23     x=Find(x),y=Find(y);
24     if(x!=y)
25         father[x]=y;
26 }
27 int main ()
28 {
29     int t;
30     int x,y;
31     scanf("%d",&t);
32     for(int Case=1; Case<=t; ++Case)
33     {
34         int flag=1;
35         scanf("%d%d",&n,&m);
36         init();
37         for(int i=0; i<m; ++i)
38         {
39             scanf("%d%d",&x,&y);
40             if(Find(x)==Find(y))
41                 flag=0;
42             if(sex[x]==0)
43                 sex[x]=y;
44             else
45                 Union(sex[x],y);
46             if(sex[y]==0)
47                 sex[y]=x;
48             else
49                 Union(sex[y],x);
50         }
51         printf("Scenario #%d:
",Case);
52         if(flag)
53             printf("No suspicious bugs found!

");
54         else
55             printf("Suspicious bugs found!

");
56     }
57 }
View Code

 hdu 4496 D-City

http://acm.hdu.edu.cn/showproblem.php?pid=4496

解题思路:通化邀请赛的题目,并查集。

题目说的是N个点M条边,现在让你输出的是删除前k条边后,这个图的联通分支数是多少。

倒过来做,一开始的时候每个节点都是一个联通分支,所以分支数是N,然后每次加入一条边的时候,看一下这条边的两个端点是不是在同一个分支里,如果不是,合并并且分支数-1,将分支压入栈中。

最后输出就可以了。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <stack>
 5 #define maxlen 10010
 6 using namespace std;
 7 int father[maxlen];
 8 int n,m;
 9 char str[100010];
10 struct node
11 {
12     int s,e;
13 }p[100010];
14 void init()
15 {
16     for(int i=0;i<=n;++i)
17         father[i]=i;
18 }
19 int inline Find(int x)
20 {
21     return father[x]==x?x:father[x]=Find(father[x]);
22 }
23 void inline Union(int x,int y)
24 {
25     x=Find(x),y=Find(y);
26     if(x!=y)
27         father[x]=y;
28 }
29 int main ()
30 {
31     while(scanf("%d%d",&n,&m)!=EOF)
32     {
33         for(int i=0;i<m;++i)
34             scanf("%d%d",&p[i].s,&p[i].e);
35         init();
36         int cnt=n;
37         stack<int>s;
38         for(int i=m-1;i>=0;--i)
39         {
40             s.push(cnt);
41             if(Find(p[i].s)!=Find(p[i].e))
42             {
43                 Union(p[i].s,p[i].e);
44                 cnt--;
45             }
46         }
47         while(!s.empty())
48         {
49             printf("%d
",s.top());
50             s.pop();
51         }
52     }
53 
54 }
View Code

 uva 11987 Almost Union-Find

题目大意:

给了三种操作:

1 p q 合并

2 p q 把p移动到q集合中

3 p 求p所在集合的元素个数以及元素之和

分析:

关键就是第二个操作,事实上移动操作就是删除+合并操作。

删除操作具体可以看我上一篇并查集专题最后一题

可以增加一个id[i]数组表示i这个数现在真实的对应的下标,在删除操作的时候,将id改为新的虚拟父亲,从新初始化既可以了。

其他两个值得维护也比较简单,就是在合并的是后把被合并的两个值加到合并的集合中去就可以了。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #define maxlen 200010
 5 using namespace std;
 6 int father[maxlen],id[maxlen];
 7 int num[maxlen];
 8 long long sum[maxlen];
 9 int n,m;
10 int cnt;
11 void init()
12 {
13     for(int i=1;i<=n;++i)
14     {
15         id[i]=father[i]=sum[i]=i;
16         num[i]=1;
17     }
18     cnt=n;
19 }
20 int Find(int x)
21 {
22     return father[x]==x?x:father[x]=Find(father[x]);
23 }
24 void Union(int x,int y)
25 {
26     x=Find(id[x]),y=Find(id[y]);
27     father[x]=y;
28     num[y]+=num[x];
29     sum[y]+=sum[x];
30 }
31 void Delete(int x)
32 {
33     int xx=Find(id[x]);
34     --num[xx];
35     sum[xx]-=x;
36     id[x]=(++cnt);//从新初始化
37     father[id[x]]=id[x];
38     num[id[x]]=1;
39     sum[id[x]]=x;
40 }
41 int main()
42 {
43     while(scanf("%d%d",&n,&m)!=EOF)
44     {
45         init();
46         for(int i=0;i<m;++i)
47         {
48             int cmd,x,y;
49             scanf("%d",&cmd);
50             if(cmd==1)
51             {
52                 scanf("%d%d",&x,&y);
53                 if(Find(id[x])!=Find(id[y]))
54                     Union(x,y);
55             }
56             else if(cmd==2)
57             {
58                 scanf("%d%d",&x,&y);
59                 if(Find(id[x])!=Find(id[y]))
60                 {
61                     Delete(x);
62                     Union(x,y);
63                 }
64             }
65             else 
66             {
67                 scanf("%d",&x);
68                 x=Find(id[x]);
69                 printf("%d %lld
",num[x],sum[x]);
70             }
71         }
72     }
73 }
View Code
原文地址:https://www.cnblogs.com/shuzy/p/3253823.html