[并查集] codevs1073 家族(并查集的一般写法和两种优化)

题目

codevs1073

思路

即给一个无向图,判断两个结点是否连通。
并查集
路径优化的内容上面讲了,对于另一个优化:按秩合并:
在合并两个子树的时候,分别设两个子树的结点个数为tot[i],tot[j]。若tot[i]>tot[j],那么理想的方法是把j子树接到i子树上,原因是,这样做只会有tot[j]个结点的深度加一,而另外一种接法需要有tot[i]个结点的深度加一。当然更多的结点深度越小越好。

代码

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <vector>
#define _for(i,a,b) for(int i = a; i<b; i++)
#define _rep(i,a,b) for(int i = a; i<=b; i++)
using namespace std;

const int maxn = 5000+10;
int n, m, p, fa[maxn], tot[maxn];

int getfa(int x){
    if (fa[x] == x) return x;
    fa[x] = getfa(fa[x]);   // 路径压缩 
    return fa[x];
}

int hebing(int x, int y){
    x = getfa(x);
    y = getfa(y);
    if (tot[x] > tot[y]) swap(x,y);
    fa[x] = y;
    tot[x] += tot[y];
}

int main(){
    scanf("%d%d%d",&n,&m,&p);

    _rep(i,1,n){
         fa[i] = i;
         tot[i] = 1;
    }

    int u,v;
    _for(i,0,m){
        scanf("%d%d",&u,&v);
        hebing(u,v);
    }

    _for(i,0,p){
        scanf("%d%d",&u,&v);
        if (getfa(u) == getfa(v)) printf("Yes\n");
        else printf("No\n");
    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/icecab/article/details/81514496