并 查 集 ! ! !

并查集的笔记

(wtcl以至于只能发这种cj的内容)
并查集,用于解决判断连通性。最好情况下应该是能达到log(n)级别的。这比dfs和bfs快多了啊啊啊啊啊。

并查集,顾名思义,它分为两块:

介绍大致思路

用一个id数组,表示自己的爸爸是谁。这样一来,
判断连通性的问题就转换成了看自己的爸爸是不是一个。
上代码:

typedef long long ll;
ll n,m,x,y,z,id[N];

合并

比如说,x与y联通关系。
那我们不妨令y是x的爸爸。
那么,id[x]=y;用这句话就能让一个人轻松变你儿子。
上代码:

void unite(ll x,ll y){
    ll xi=find(x),yi=find(y);
    id[xi]=yi;
}

查找

我们顺着儿子到爸爸的关系一个一个找下去:
你要找x[i]的爸爸,就相当于找d[x[i]]的爸爸,一直找下去,总会到一个尽头。
这个人,便是你爸爸的爸爸的爸爸的爸爸的爸爸的爸爸的爸爸的爸爸的爸爸的爸爸的爸爸的爸爸的爸爸的爸爸的爸爸的爸爸的爸爸的爸爸的爸爸的爸爸的爸爸的爸爸的爸爸的爸爸。
这个人就是你要找的祖先
上代码:

ll find(ll x){
    if(id[x]==x)return x;
    return id[x]=find(id[x]);
}

判连通

假设有两个点:xi和yi
你如果是连通的,那么xi的爸爸就等于y的爸爸。

整体模板代码部分 ( 好激动 ) :

#include<iostream>
#define N 100010
using namespace std;
typedef long long ll;
ll n,m,x,y,z,id[N];
ll find(ll x){
    if(id[x]==x)return x;
    return id[x]=find(id[x]);
}
void unite(ll x,ll y){
    ll xi=find(x),yi=find(y);
    id[xi]=yi;
}   
int main(){
    cin>>n>>m;
    for(ll i=0;i<n;i++)id[i]=i;
    while(m--){
        cin>>z>>x>>y;
        if(z==1) unite(x,y);
        else if(z==2){
            if(find(x)==find(y))cout<<"Y"<<endl;
            else cout<<"N"<<endl;
        }
    }
    return 0;
}

也就那么几行,不是特别难,对吧?

猜你喜欢

转载自www.cnblogs.com/tushukai/p/11546291.html