You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2.3 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

##AcWing 836. 合并集合

一、题目描述

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

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

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

输入格式 第一行输入整数 nm

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

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

每个结果占一行。

数据范围 1≤n,m≤10^5

输入样例:

4 5
M 1 2
M 3 4
Q 1 2
Q 1 3
Q 3 4

输出样例:

Yes
No
Yes

二、题目解析

最裸并查集 1、将两个集合合并。

2、询问两个元素是否在一个集合当中 ,近乎O(1)时间内支持两个操作

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

  • 如何判断树根? if(p[x]==x)

  • 如何求x的集合编号? find(x)

  • 如何合并两个集合? p[find(a)] = find(b)

三、实现代码

#include <bits/stdc++.h>

using namespace std;
const int N = 100010;

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--) {
        char op;
        int a, b;
        cin >> op >> a >> b;
        if (op == 'M')
            p[find(a)] = find(b); // a家族加入b家族
        else {
            if (find(a) == find(b))
                puts("Yes");
            else
                puts("No");
        }
    }
    return 0;
}