首页 > 其他分享 >并查集

并查集

时间:2023-03-23 21:47:35浏览次数:33  
标签:路径 return int 查集 祖先 root find

并查集主要包括初始化、寻根以及合并三个操作。

例如a、b、c、d、e,初始化他们的祖先为本身。

寻根操作:

int find_root(int x){//非路径压缩
  return x==s[x]?x:finde_root(s[x]);
}

上述寻根操作,没有对路径进行压缩。具体表现为如果a的祖先是b,b的祖先是c,c的祖先是d。那么在对a进行寻根的时候会查找三次,即树太高了

int find_root(int x){//路径压缩
    if(x!=s[x]) s[x]=find_root(s[x]);
    return s[x];
}

给出非递归版本

int find_root(int x){
    int r=x;
    while(r!=s[r]) r=s[r];//找到x最大的祖先
    int i=x;
    int j;
    while(i!=r){
        j=s[i];//先把i此时的祖先存好
        s[i]=r;//然后把此时的祖先的祖先设为最终的祖先即r
        i=j;//i变为上面的一个祖先
    }
    return r;
}

 

使用了路径压缩之后,相当于a,b,c的祖先直接就是d,那么只需要查询一次即可,使用路径压缩的时候,我们每次寻根的时候都需要调用find_root,这样是为了路径能一直更新。

合并操作:

void merge_set(int x,int y){
    x=find_root(x);
    y=find_root(y);
    if(x!=y){
        s[x]=y;
    }
}

合并之前我们调用了find_root函数找到x和y的祖先,按理来说既然已经使用了路径压缩,那么直接使用s[x]和s[y]也是可以达到找到祖先的效果,但是要考虑到一点,如果此时路径还没压缩,那么直接找找不到祖先节点。

例子:洛谷P3367

题目描述

如题,现在有一个并查集,你需要完成合并和查询操作。

输入格式

第一行包含两个整数 �,�N,M ,表示共有 �N 个元素和 �M 个操作。

接下来 �M 行,每行包含三个整数 ��,��,��Zi​,Xi​,Yi​ 。

当 ��=1Zi​=1 时,将 ��Xi​ 与 ��Yi​ 所在的集合合并。

当 ��=2Zi​=2 时,输出 ��Xi​ 与 ��Yi​ 是否在同一集合内,是的输出 Y ;否则输出 N 。

输出格式

对于每一个 ��=2Zi​=2 的操作,都有一行输出,每行包含一个大写字母,为 Y 或者 N 。

#include<bits/stdc++.h>
using namespace std;
const int MAXN=10004;
int s[MAXN];
int find_root(int x){
    if(x!=s[x]) s[x]=find_root(s[x]);
    return s[x];
}
void merge_set(int x,int y){
    x=find_root(x);
    y=find_root(y);
    if(x!=y){
        s[x]=y;
    }
}
void isOneSet(int x,int y){
    x=find_root(x);
    y=find_root(y);
    if(s[x]!=s[y]){
         cout<<'N'<<endl;
    }else
        cout<<'Y'<<endl;
}
void init_set(int N){
    for(int i=0;i<N;i++){
        s[i]=i;
    }
}
int main()
{
    int N,M,x,y,z;
    cin>>N>>M;
    init_set(N);
    for(int i=0;i<M;i++){
        cin>>z>>x>>y;
        if(z==1){
            merge_set(x,y);
        }else{
            isOneSet(x,y);
        }
    }
    return 0;
}

 

标签:路径,return,int,查集,祖先,root,find
From: https://www.cnblogs.com/hailanben/p/17249525.html

相关文章

  • How Many Tables HDU - 1213(并查集/连通块数量)
    题意:朋友的朋友是朋友如果A认识B,B认识C,那么ABC三个人就可以坐在同一张桌子上但如果A认识B,C认识D,那我们就默认AB和CD不认识,需要准备两张桌子现在我们需要你计算出,我们一......
  • 2023-03-23_并查集
    并查集两个点之间在树或图中是否连通的问题。1什么是并查集?连接问题网络中节点间的连接状态数学中的集合类实现连接问题与路径问题:解决路径问题便一定可以解......
  • 并查集模板
    并查集(Union(并),Find(查),Set(集))一般用树的形式保存集合,但是是用数组模拟的树对于并查集树上的所有点,只有根结点是p[x]=x的,其他的p[x]都是父结点那么就可以通过whil......
  • 并查集拓展
    上一期由于上一期过水,只讲了一点点序列的问题,然而在乱逛看题解的时候,发现其实并查集能做到的远远不止图论与有限步骤序列问题,今天就从一(不会讲模板的)开始来记录一下并查集......
  • TZOJ 5784: 团伙 并查集
    描述 在某城市里住着n个人,任何两个认识的人不是朋友就是敌人,而且满足:1、我朋友的朋友是我的朋友;2、我敌人的敌人是我的朋友;所有是朋友的人组成一个团伙。告诉你关于......
  • ABC 293 ABCD(并查集)
    A-SwapOddandEven#include<bits/stdc++.h>usingnamespacestd;typedeflonglongLL;typedefpair<LL,LL>PII;constLLMAXN=1e18,MINN=-1e18;constLLN=1e6......
  • 并查集一
    并查集一当我们需要快速判断两个元素是否归属于同一个集合或者将两个集合合并时,就会使用并查集 #include<iostream>usingnamespacestd;constintN=1e5+1......
  • [蓝桥杯 2019 省 A] 修改数组 ———并查集练习(大学复健)
    本题拿到第一反应桶排序思想似乎可以水过,但是很明显出问题了。#include<bits/stdc++.h>usingnamespacestd;intN;inlineintkd(){ intx=0,f=1;charch=getchar......
  • 蓝桥杯 & 青蛙过河(最快贪心) (不用并查集)
      点击查看代码#include<bits/stdc++.h>usingnamespacestd;typedeflonglongll;constintN=1000000+7;lla[N];llb[N];llc[N];lln,x;boolcheck(ll......
  • 并查集模板
    #include<bits/stdc++.h>usingnamespacestd;intfa[10005];intm,n;intfind(intx){ if(fa[x]!=x){ fa[x]=find(fa[x]); } returnfa[x];}booljudge(intx,......