并查集

//初始化
int father[N];
for(int i=1; i<=N; i++){
    father[i] = i; //令father[i]为1也可
}
//查找
int findFather(int x){
    //由于x在下面的while中会变成根结点,因此先把原来的x先保存下
    int a = x;
    while(x != father[x]){  //如果不是根结点,继续循环
        x = father[x]; //获得自己的父亲结点
    }
    //路径压缩(可不写)把路径上的所有结点的father都改成根结点
    while(a != father[a]){
        int z = a;
        a = father[a];
        father[z] = x;
    }
    return x;
}
//较小时间复杂度的查找(路径压缩)
int findFather(int v){
    if(v == father[v]) return v;   //找到根结点
    else{
        int F = findFather(father[v]);  //递归寻找father[v]的根结点
        father[v] = F;   //将根结点F赋给father[v]
        return F;   //返回根结点
    }
}
//合并
void Union(int a, int b){
    int faA = findFather(a); //查找a的根结点,记为faA
    int faB = findFather(b); //查找b的根结点,记为faB
    if(faA != faB){  //如果不属于同一个集合
        father[faA] = faB;   //合并
    }
}
原文地址:https://www.cnblogs.com/dear_diary/p/8616216.html