题目链接:点击打开链接
题目大意:
一共有N个人,给出M个操作分为两种:
1、A a b :提问a和b是否是同一个帮派的。有三种答案:是,不是和不确定
2、D a b :a和b不是同一个帮派的。
解题思路:
种类并查集,在一个集合里的证明他们之间有关系,种类里有0,和1两种。0代表着同父节点相同势力,1代表不同。
主要是不在同一集合时合并和查找操作;
#include<iostream>
#include<cstdio>
#include<string>
using namespace std;
const int N = 100005;
int vis[N];//与父节点属于同一帮派为0,不一帮派为1
int father[N];
int find(int x) {//每次find后vis的值将变正确
if (father[x] != x) {
int t = find(father[x]);
此处很重要,是通过这个节点与原来父节点的关系(是否是同一集合的问题)求这个节点现在与根节点的关系(异或关系)
vis[x] = (vis[father[x]] + vis[x]) % 2;
father[x] = t;
}//顺序不可变
return father[x];
}
void merge(int x,int y) {
int a = find(x);
int b = find(y);
father[a] = b;//将x所在的树连接到y所在的树的下边
if (vis[y] == 0)vis[a] = 1 - vis[x];//如果y与b在同一帮派,又因为y与x在不同帮派,推出a和b在不在同一帮派
else vis[a] = vis[x];//与上相同
}
int main() {
int T;
cin >> T;
while (T--) {
int n, t;
char temp[20];
cin >> n >> t;
for (int i = 0; i <= n; i++)father[i] = i;
memset(vis, 0, sizeof(vis));
string s;
while (t--) {
int a, b;
scanf("%s %d %d", temp, &a, &b);//输入数据
s = temp;//char->string
if (s == "A") {
if (find(a) != find(b)) {//这里面包含find函数,所以vis值正确,为后面判断做铺垫
printf("Not sure yet.\n");
continue;
}
else {
if (vis[a]==vis[b])printf("In the same gang.\n");//上面的find会使vis正确
else printf("In different gangs.\n");
}
}
else merge(a, b);//两个合到同一集合
}
}
}