Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 23915 | Accepted: 7167 |
Description
Input
Output
Sample Input
1 5 5 A 1 2 D 1 2 A 1 2 D 2 4 A 1 4
Sample Output
Not sure yet. In different gangs. In the same gang.
Source
Not sure yet.
如果find(x)等于 find(y) ,但是他们的r不等,说明属于不同帮派,输出In different gangs.
如果他们的r相等,说明属于同一个帮派,则输出In the same gang
注意:1.find()函数寻找根节点的时候要不断的更新 r
根据子节点与父亲节点的关系和父节点与爷爷节点的关系,推导子节点与爷爷节点的关系
如果 a 和 b 的关系是 r1, b 和 c 的关系是 r2,
那么 a 和 c 的关系就是 (r1+r2)%2 . PS:因为只用两种情况所以对 2 取模。
如果实在不好理解,那么我们就枚举推理一下,共有 2*2 = 4种情况:
(a, b) (b, c) (a, c) (r1+r2)%2
0 0 0 0 a 和 b是同类 , b 和 c 是同类, 所以 a 和 c 也是同类
0 1 1 1 a 和 b是同类 , b 和 c 是异类, 所以 a 和 c 也是异类
1 0 1 1 a 和 b是异类 , b 和 c 是同类, 所以 a 和 c 是异类
1 1 0 0 a 和 b是异类 , b 和 c 是异类, 所以 a 和 c 是同类
2.Union()联合两棵树的时候也要更新两棵树的根的关系
定义:fx 为 x的根节点, fy 为 y 的根节点
联合时,使得 p[fx] = fy; 同时也要寻找 fx 与 fy 的关系。关系为:(r[x]+r[y]+1)%2
如何证明?
fx 与 x 的关系是 r[x],
x 与 y 的关系是 1 (因为确定是不同类,才联合的),
y 与 fy 关系是 r[y],模 2 是因为只有两种关系
所以又上面的一点所推出的定理可以证明 fx 与 fy 的关系是: (r[x]+r[y]+1)%2
/* D Accepted 916 KB 329 ms C++ 1120 B 2013-04-08 18:29:33 */ #include<cstdio> const int maxn = 100000+10; int p[maxn]; //存父亲节点 int r[maxn]; //存与根节点的关系,0 代表同类, 1代表不同类 int find(int x) //找根节点 { if(x == p[x]) return x; int t = p[x]; //记录父亲节点 方便下面更新r[] p[x] = find(p[x]); r[x] = (r[x]+r[t])%2; //根据子节点与父亲节点的关系和父节点与爷爷节点的关系,推导子节点与爷爷节点的关系 return p[x]; //容易忘记 } void Union(int x, int y) { int fx = find(x); //x所在集合的根节点 int fy = find(y); p[fx] = fy; //合并 r[fx] = (r[x]+1+r[y])%2; //fx与x关系 + x与y的关系 + y与fy的关系 = fx与fy的关系 } void set(int n) { for(int x = 1; x <= n; x++) { p[x] = x; //自己是自己的父节点 r[x] = 0; //自己和自己属于同一类 } } int main() { int T; int n, m; scanf("%d", &T); while(T--) { scanf("%d%d%*c", &n, &m); set(n); char c; int x, y; while(m--) { scanf("%c%d%d%*c", &c, &x, &y); //注意输入 //printf("%c\n", c); if(c == 'A') { if(find(x) == find(y)) //如果根节点相同,则表示能判断关系 { if(r[x] != r[y]) printf("In different gangs.\n"); else printf("In the same gang.\n"); } else printf("Not sure yet.\n"); } else if(c == 'D') { Union(x, y); } } } return 0; }