【模板】并查集

//洛谷P3367

并查集算法也算是算法中的经典了,它可以用O(logn)的时间支持一张图中集合的合并与查询。

这里,我们首先用一个数组fa[x]来表示以x为编号的祖先的编号(*每一个点的初始祖先为它自身)。

然后就是并查集的重中之重:find()函数!!!

int find(int x){
    if(x==fa[x]) return x;
    else return fa[x]=find(fa[x]);
}

find(x)就是查询点x 所在集合的祖先,并更新fa[x]。

这里注意,如果没有fa[x]=find(fa[x]),而只是return find(fa[x])的话,操作久了,树就会退化成一个链,而失去其logn的时间复杂度,很容易T。

 

然后,是实现集合之间的合并:merge()

void merge(int x,int y){
    if(find(x)!=find(y)) 
        fa[find(x)]=fa[y];
}

这样就把x 所在集合的祖先接在y 所在的集合的祖先下面,其中fa[find(x)]=fa[y]也可写成fa[fa[x]]=fa[y]。

 

最后就是并查集的查询操作:query()

bool query(int x,int y){
    if(find(x)==find(y)) return true;
    else return false;    
}

如果x,y祖先相同,那么他们就在一个集合中,反之则不然。

最后代码整合一下如下:

#include<algorithm>
#include<iostream>
#include<cstdio>
#include<vector>
#define maxn 10000 + 10
using namespace std;
int n,m,opr,v,u;
int fa[maxn];
int find(int x){
    if(x==fa[x]) return x;
    else return fa[x]=find(fa[x]);
}
void merge(int x,int y){
    if(find(x)!=find(y)) 
        fa[find(x)]=fa[y];
}
bool query(int x,int y){
    if(find(x)==find(y)) return true;
    else return false;    
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) fa[i]=i;
    for(int i=1;i<=m;i++) {
        scanf("%d%d%d",&opr,&u,&v);
        if(opr==1) merge(u,v);
        else if(query(u,v)) printf("Y\n"); 
             else printf("N\n");
    }
    return 0;
}

 

posted @ 2017-12-01 17:02  XjzLing  阅读(240)  评论(0编辑  收藏  举报