CDOJ1927 爱吃瓜的伊卡洛斯(2) 【并查集】启发式合并+set

伊卡洛斯很爱吃西瓜。一次,他来到一个西瓜摊旁,发现水果摊有N个西瓜,西瓜有红色、黄色、绿色、蓝色……等等数不清的颜色。 伊卡洛斯很想知道知道一些信息,便于老板交谈了起来。 当老板的话的第一个字符为”A”时,老板会告诉伊卡洛斯一些信息,格式如下: A x y 1 这句话表示第x个西瓜和第y个西瓜是同一种颜色的。 A x y 2这句话表示第x个西瓜和第y个西瓜是不同种颜色的。

当然,为了考验伊卡洛斯有没有认真听, 老板也会时不时问伊卡洛斯一些问题,格式如下: Q x y 这句话表示询问第x个西瓜和第y个西瓜是不是同一种颜色,如果确定为同一种颜色,伊卡洛斯需要回答1;确定为不同种颜色,伊卡洛斯需要回答2;无法确定时伊卡洛斯回答3。 注意,伊卡洛斯是根据已获得的信息来回答的。也就是只有这个问题之前的信息才为已知信息。

老板说,只有回答对他全部的问题,伊卡洛斯才能吃到瓜,他聪明的想到了让你来帮助他。

Input

第一行包含两个整数NMN是西瓜总数,M是以AQ开头的老板的话总和。
以下M行,每行包含一条老板的话。形式有A x y 1A x y 2Q x y。 1N100000 1M200000 1X,YN 数据保证没有矛盾

Output

对于每一条Q指令,输出1/2/3代表两个西瓜颜色的关系。

Hint

西瓜的颜色可以有无数多种!

思路:这题颜色有无穷多种,所以不能按照普通的并查集分块求对立。 
可以用set存每一个集合的对立(不同颜色)集合,如果两个x,y颜色相同时,合并两个集合的对立集合。 
合并的时候尽量将小的集合合并到大的集合中去。 

 1 #include <algorithm>
 2 #include <iostream>
 3 #include <cstdio>
 4 #include <cmath>
 5 #include <cstring>
 6 #include <set>
 7 using namespace std;
 8 
 9 const int N = 1e5+6;
10 int f[N];
11 set<int> s[N];
12 
13 int find(int x)
14 {
15     if(x==f[x])return x;
16     else return f[x]=find(f[x]);
17 }
18 
19 void unite(int x,int y)
20 {
21     x = find(x);
22     y = find(y);
23     if(x!=y)
24     {
25         if(s[x].size()>s[y].size())swap(x,y);
26         // s[x] size is small
27         f[x]=y;
28         if(s[x].size())
29         {
30             set<int>:: iterator it;
31             for(it = s[x].begin(); it != s[x].end(); it++)
32                 s[y].insert(find(*it));
33         }
34     }
35     return;
36 }
37 
38 int main()
39 {
40     int n,m;
41     char op[6];
42     scanf("%d%d",&n,&m);
43     for(int i=1;i<=n;i++)
44         f[i]=i;
45     while(m--)
46     {
47         scanf("%s",&op);
48         int x,y,z;
49         if(op[0] =='A')
50         {
51             scanf("%d%d%d",&x,&y,&z);
52             if(z==1)
53                 unite(x,y);
54             else
55             {
56                 s[find(x)].insert(find(y));
57                 s[find(y)].insert(find(x));
58             }
59         }
60         else
61         {
62             scanf("%d%d",&x,&y);
63             int xx = find(x);
64             int yy = find(y);
65             if(xx==yy)printf("1\n");
66             else if(s[xx].find(yy)!=s[xx].end() || s[yy].find(xx)!=s[yy].end())
67                 printf("2\n");
68             else printf("3\n");
69         }
70     }
71     return 0;
72 }

 

posted @ 2018-06-14 20:20  demianzhang  阅读(433)  评论(0编辑  收藏  举报