又是一道典型的并查集应用
社会上有两个黑帮
任给你2个人的编号,若前面字母是'D',则这两个人属于不同黑帮
若前面字母是'A',则询问你这两个人是否属于同一个黑帮或是不确定
解法:
令p[x]为x的父节点,若p[x]!=p[y]则两个人中至少有一个人在之前的数据中还没出现过,不能确定状态
若p[x]==p[y]且r[x]==r[y],则两个人属于同一个黑帮
否则属于不同的黑帮
用并查集的难点在于如何路径压缩
对于每次给出的数据,给出'D a b'
x = find(a);
y = find(b);
若当前p[x]==p[y],则两个人均出现过,不需要操作
否则令p[y]==x,将y的父节点设为x,对应r[y]应该怎么求呢?
对于r[a] r[b],因为在find的过程中进行了路径压缩,所以当前r[a] r[b]对应的是和x y的关系
现下列出一种情况:
当r[x] == r[a] =0 r[y]==r[b]=0时
说明a x属于同一个黑帮,b y属于同一个黑帮
因为D a b,故x y必然不属于同一个黑帮
所以处理后r[y]应该等于1
其他情况不再一一列举
给出对应关系r[y] = r[a]^1^r[b]//对应同或关系
代码如下:
#include <cstdio>
#include <iostream>
#define MAXN 100001
using namespace std;
int r[MAXN], p[MAXN];
int find(int x) {
int tmp;
if(x != p[x]) {
tmp = p[x];
p[x] = find(p[x]);
r[x] ^= r[tmp];
}
return p[x];
}
int main(void) {
int T, a, b, x, y, i, n, m;
char ch[10];
scanf("%d", &T);
while(T--) {
scanf("%d%d", &n, &m);
for(i=1; i<=n; ++i) {
p[i] = i;
r[i] = 0;
}
while(m--) {
scanf("%s%d%d", ch, &a, &b);
x = find(a);
y = find(b);
if(ch[0] == 'A') {
if(x != y)
puts("Not sure yet.");
else if(r[a] == r[b])
puts("In the same gang.");
else puts("In different gangs.");
} else {
if(x != y) {
p[y] = x;
r[y] = r[a]^1^r[b];
}
}
}
}
return 0;
}