acwing 836. 合并集合 (并查集)

并查集功能:近乎 O(1)

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

如果上述两个功能用暴力做法:

  • 询问两个元素是否在一个集合中
// 时间复杂度是O(1)的
belong[x] = a
if(belong[x] == belong[y])   
  • 将两个集合合并
    这时暴力做法就需要将小集合合并到大集合中,操作效率低,这里可以用并查集优化

并查集原理:
每一个集合用一颗树来维护。有以下规定。

  1. 根节点是集合代表元素,根节点的标号就是集合的编号
  2. 记录每一个点都存储父节点是谁 p[x] 表示x 的父节点

问题1 :如何判断树跟 : if (p[x] == x)
问题2 :如何求x的集合编号 : while(p[x] != x) x = p[x];, 只要不是树根,一直往上走
问题3 : 如何合并两个集合 : 根节点加一条线即可,p[x] 是x集合编号,p[y] 是y的集合编号。p[x] = y.
在这里插入图片描述
并查集还有一个优化:
当集合中的一个点x 从根节点需要往下查找3次,查找第一遍后,可以修改这条路径上所有点全部指向根节点,后面查找则可以一次查找成功,所以这里的时间复杂度近乎O(1).

在这里插入图片描述

题目

一共有 n 个数,编号是 1∼n,最开始每个数各自在一个集合中。

现在要进行 m 个操作,操作共有两种:

M a b,将编号为 a 和 b 的两个数所在的集合合并,如果两个数已经在同一个集合中,则忽略这个操作;
Q a b,询问编号为 a 和 b 的两个数是否在同一个集合中;
输入格式
第一行输入整数 n 和 m。

接下来 m 行,每行包含一个操作指令,指令为 M a b 或 Q a b 中的一种。

输出格式
对于每个询问指令 Q a b,都要输出一个结果,如果 a 和 b 在同一集合内,则输出 Yes,否则输出 No。

每个结果占一行。

数据范围
1≤n,m≤105
输入样例:
4 5
M 1 2
M 3 4
Q 1 2
Q 1 3
Q 3 4
输出样例:
Yes
No
Yes

核心:
find 函数

code:

#include <iostream>

using namespace std;

const int N = 100010;
int p[N], n, m;   //p[] 是存储父节点  当 p[x] == x  x就是树根

// 也是集合编号
int find(int x)   // 返回的是x 的祖宗节点  + 路径压缩  (返回x 的编号 + 路径压缩)
{
    if(p[x] != x)   // != 说明不是根节点 
        p[x] = find(p[x]);   // 让它的父节点 = 它的祖宗节点
    return p[x];
}

int main()
{
    scanf("%d%d", &n, &m);
    for(int i=1; i<=n; i++)   p[i] = i;   // 所以节点指向自己
    
    while(m --)
    {
        char op[2];
        int a, b;
        scanf("%s%d%d", op, &a, &b);
        
       if(*op == 'M') 
       {
           //p[find(a)] = find(b);
           p[find(b)] = find(a);   // a 的祖宗节点 = b的祖宗节点,两个集合加了一条线
       }
       else 
       {
           if(find(a) == find(b)) puts("Yes");
           else puts("No");
       }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值