Loading

算法学习笔记01: 并查集

并查集

并查集

并查集是一种用于管理元素所属集合的数据结构,实现为一个森林,其中每棵树表示一个集合,树中的节点表示对应集合中的元素。

并查集支持两种操作:

  • 合并 (Union): 合并两个元素所属集合 (合并对应的树)
  • 查询 (Find): 查询某个元素所属集合 (查询对应的树的根节点),这可以用于判断两个元素是否属于同一集合

路径压缩:

查询过程中经过的每个元素都属于该集合,我们可以将其直接连到根节点以加快后续查询

合并:

要合并两棵树,我们只需要将一棵树的根节点连到另一棵树的根节点

题目【洛谷P3367】

洛谷传送门

题面

题目描述

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

输入格式

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

接下来 \(M\) 行,每行包含三个整数 \(Z_i,X_i,Y_i\)

\(Z_i=1\) 时,将 \(X_i\)\(Y_i\) 所在的集合合并。

\(Z_i=2\) 时,输出 \(X_i\)\(Y_i\) 是否在同一集合内,是则输出 Y ;否则输出 N

输出格式

对于每一个 \(Z_i=2\) 的操作,都有一行输出,每行包含一个大写字母,为 Y 或者 N

题解

#include <stdio.h>

int fa[200010];
int size[200010];    // size数组记录各集合的秩

int find(int x) {
    if (x == fa[x]) {
        return x;
    }
    return fa[x] = find(fa[x]);     // 路径压缩,把路径上的所有节点都直接指向根节点
} 

void merge(int x, int y) {
    int root_x = find(x);
    int root_y = find(y);
    if (size[root_x] > size[root_y]) {  // 比较两集合秩的大小,然后按秩合并
        fa[root_y] = root_x;
        size[root_x] += size[root_y];
    } else {
        fa[root_x] = root_y;
        size[root_y] += size[root_x];
    }
}

int main(int argc, const char *argv[]) {
    int n, m;
    scanf("%d%d", &n, &m);

    int i;
    for (i = 1; i <= n; i++) {
        fa[i] = i;
        size[i] = 1;
    }

    while(m--) {
        int z, x, y;
        scanf("%d%d%d", &z, &x, &y);
        if (z == 1) {
            merge(x, y);
        } else if (z == 2) {
            if (find(x) == find(y)) {
                puts("Y");
            } else {
                puts("N");
            }
        }
    }

    return 0;
}
posted @ 2025-04-20 18:03  Chase_Tsai  阅读(38)  评论(0)    收藏  举报