现在我们假定 fa[i] 表示第 i 个人的老大是谁
现在我们有甲,乙,丙三个人(分别用 a, b, c 表示)
假设甲和乙打架了,甲做了丙的小弟。则有 fa[a] = b,后来甲打赢了丙那么丙就是甲的小弟了。有 fa[c]=a,
但是如果我们这样表示,丙不能直接知道甲,自己人要打自己人啊,所以昂我们必须直接让丙的大哥变成最大的老大。
简单来说就是谁先当了老大,谁就是黑社会老大,其他都是小弟要跟他混的
我的代码
#include <iostream>
#include <cstdio>
using namespace std;
const int N = 1e5 + 9;
int fa[N], m, n;
//查询是否属于同一个集合
int find(int x){
if(x == fa[x]) return x;
return fa[x] = find(fa[x]);
}
//连接两个集合
void insert(int x,int y){
int f1 = find(x), f2 = find(y);//查找两个数所在的集合
if(f1 != f2) fa[f1] = f2;
}
int main(){
scanf("%d%d",&n,&m);
//假设原来都是没有合并的集合 每一个数都是一个集合(自己是自己的老大)
for(int i = 1; i <= n; i++) fa[i] = i;
for(int i = 1; i <= m; i++){
char op[2];
int x, y ;
scanf("%s%d%d",op,&x, &y);
if(op[0] == 'M') insert(x, y); // y 以后就要和 x 的老大混了
else {
if(find(x) == find(y)) printf("Yes\n");
else printf("No\n");
}
}
return 0;
}
y总代码
#include <iostream>
#include <cstdio>
using namespace std;
const int N = 1e5 + 9;
int p[N], n , m;
//返回 x 的祖宗节点(路径压缩版本)
int find(int x){
if(p[x] != x) p[x] = find(p[x]);
return p[x];
}
int main(){
scanf("%d%d",&n,&m);
for(int i = 1; i <= n; i++) p[i] = i;
while(m--){
char op[2];
int a,b;
scanf("%s%d%d",op,&a,&b);
if(op[0] == 'M') p[find(a)] = find(b); // b 要跟 a 家族的老大混
else //查询是不是在同一个家族
if(find(a) == find(b)) printf("Yes\n");
else printf("No\n");
}
return 0;
}