31.Acwing基础课第836题-简单-合并集合

31.Acwing基础课第836题-简单-合并集合

题目描述

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

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

  1. M a b,将编号为 a 和 b 的两个数所在的集合合并,如果两个数已经在同一个集合中,则忽略这个操作;
  2. Q a b,询问编号为 a 和 b 的两个数是否在同一个集合中;

输入格式

第一行输入整数 n 和 m。

接下来 m 行,每行包含一个操作指令,指令为 M a bQ 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

代码:

#include <iostream>
using namespace std;

const int N = 100010;  // 定义数组最大容量,适配题目数据范围(1e5级别)
int n,m;               // n:元素总数;m:操作次数
int p[N];              // 并查集核心数组:p[x] 表示 x 的父节点

int find(int x)//返回x的祖宗节点 + 路径压缩
{
    if(p[x] != x) p[x] = find(p[x]);  // 递归找祖宗,并把x的父节点直接指向祖宗(路径压缩)
    return p[x];                      // 返回x的祖宗节点
}

int main()
{
    scanf("%d%d", &n, &m);  // 读入元素总数n,操作次数m(用scanf比cin快,适配大数据)
    
    // 初始化并查集:每个元素的父节点是自己,自成一个集合
    for(int i = 1; i <= n; i++) p[i] = i;
    
    while(m--)  // 处理m次操作
    {
        int a, b;
        char op[2];  // 存储操作符(如'M'/'Q'),用数组避免字符读取问题
        scanf("%s%d%d", op, &a, &b);  // 读入操作符、两个元素a和b
        
        if(op[0] == 'M')  // 合并操作:把a的祖宗节点的父节点指向b的祖宗节点
            p[find(a)] = find(b);
        else  // 查询操作:判断a和b是否同属一个集合(祖宗是否相同)
        {
            if(find(a) == find(b)) puts("Yes");
            else puts("No");
        }
    }
    return 0;
}
posted @ 2026-04-05 16:14  CodeMagicianT  阅读(3)  评论(0)    收藏  举报