并查集

例题

例题

例题

并查集,在一些有N个元素的集合应用问题中,我们通常是在开始时让每个元素构成一个单元素的集合,然后按一定顺序将属于同一组的元素所在的集合合并,其间要反复查找一个元素在哪个集合中

现在我们假定 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总代码(AcWing)

#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;
}
posted @ 2021-03-09 17:07  Carrot_Rui  阅读(33)  评论(0)    收藏  举报