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
第一行包含两个整数N和M,N是西瓜总数,M是以A或Q开头的老板的话总和。
以下M行,每行包含一条老板的话。形式有A x y 1或A x y 2或Q x y。 1≤N≤100000 1≤M≤200000 1≤X,Y≤N 数据保证没有矛盾
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 }