并查集

作用:
1.将两个集合合并
2.询问两个元素是否在一个集合当中

基本原理:
每个集合用一棵树来表示,树根的编号就是整个集合的编号。每个节点存储它的父节点,p[x]表示x的父节点

操作:
1.判断树根:
if(p[x]==x);

2.求x的集合编号:
while(p[x]!=x) x=p[x];

3.如何合并两个集合:
p[x]是x的集合编号,py是y的集合编号。p[x]=y;

优化:
路径压缩~o(1);

AcWing-836

AC代码:

#include <iostream>

using namespace std;

const int N=1e5+10;

int a,b;
char op[2];//操作
int n,m;
int p[N];//存储父节点

int find(int x)//返回节点祖宗
{
    if(p[x]!=x) p[x]=find(p[x]);
    return p[x];
}

int main()
{
    cin>>n>>m;
    
    for(int i=1;i<=n;i++) p[i]=i;//初始化每一个节点是一个集合 所以自己就是祖宗
    
    while(m--)
    {
        cin>>op>>a>>b;
        if(op[0]=='M') p[find(a)]=find(b);//让编号a的集合 认集合b祖宗当爹
        else
        {
            if(find(a)==find(b)) cout<<"Yes"<<endl;//两集合祖宗相等
            else cout<<"No"<<endl;
        }
    }
    return 0;
}

AcWing-837

本题在操作的过程加上了统计集合元素数量的操作

#include <iostream>

using namespace std;

const int N=1e5+10;

int a,b;
char op[3];//操作
int n,m;
int p[N];//存储父节点
int cnt[N];//根节点才有意义,表示该根节点的集合元素的数量

int find(int x)//返回节点祖宗+路径压缩
{
    if(p[x]!=x) p[x]=find(p[x]);
    return p[x];
}

int main()
{
    cin>>n>>m;
    
    for(int i=1;i<=n;i++) 
    {
        p[i]=i;//初始化每一个节点是一个集合 所以自己就是祖宗
        cnt[i]=1;
    }
    
    while(m--)
    {
        cin>>op;
        if(op[0]=='C') 
        {
            cin>>a>>b;
            if(find(a)==find(b)) continue;
            cnt[find(b)]+=cnt[find(a)];//更新数量
            p[find(a)]=find(b);//让编号a的集合 认集合b祖宗当爹
        }
        else if(op[1]=='1')
        {
            cin>>a>>b;
            if(find(a)==find(b)) cout<<"Yes"<<endl;//两集合祖宗相等
            else cout<<"No"<<endl;
        }
        else
        {
            cin>>a;
            cout<<cnt[find(a)]<<endl;//查询数量
        }
    }
    return 0;
}
posted @   Eric`  阅读(3)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
点击右上角即可分享
微信分享提示