并查集

概念:

初始状态所有点自成一个集合

包括两个基本操作:

1.把两个集合合并成一个大集合

2.查询点x和y是否属于同一个集合

优化:

按秩合并:

维护树的深度size,把深度小树的当儿子,将其根节点作为深度较大的树的树根的子节点合并

时间复杂度O(logn)

路径压缩:

找到x的根节点后,把路径上所有的节点都直接接到根节点上

时间复杂度O(logn)

code:

#include<iostream>
#include<cstdio>
#include<algorithm>
#define maxn 100010
using namespace std;
struct bcj{
    int fa[maxn];
    int size[maxn];
    void init(int n){
        for(int i=1;i<=n;i++) fa[i]=i;
        for(int i=1;i<=n;i++) size[i]=1;
    }
    int f(int x){
        return fa[x]=(fa[x]==x)?x:f(fa[x]);//"fa[x]="为路径压缩,把x直接连到根节点上 
    }
    void u(int x,int y){
        x=f(x);y=f(y);
        if(x==y) return ;//return一定要紧跟着上一行写,防止加其他东西的时候出现非法操作 
        if(size[x]>size[y]) swap(x,y);
        size[y]+=size[x];        
        fa[x]=y;//这3行代码为按秩合并,把小的树接到大的树上 
    }
}s;

int main(){
    int n,m;
    cin>>n>>m;
    s.init(n);
    for(int i=1;i<=m;i++){
        int x,y,z;
        cin>>z>>x>>y;
        if(z==1) s.u(x,y);
        else cout<<((s.f(x)==s.f(y))?"Y":"N")<<endl;
    }
    return 0;
}

题目传送门:洛谷P3367

原文地址:https://www.cnblogs.com/DReamLion/p/14384912.html