当前位置: 首页 > news >正文

【算法】【并查集】acwing算法基础837. 连通块中点的数量

题目

给定一个包含 n 个点(编号为 1∼n)的无向图,初始时图中没有边。

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

C a b,在点 a 和点 b 之间连一条边,a和 b 可能相等;Q1 a b,询问点 a 和点 b 是否在同一个连通块中,a 和 b
可能相等; Q2 a,询问点 a 所在连通块中点的数量;

输入格式

第一行输入整数 n 和 m。

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

输出格式

对于每个询问指令 Q1 a b,如果 a 和 b 在同一个连通块中,则输出 Yes,否则输出 No。

对于每个询问指令 Q2 a,输出一个整数表示点 a 所在连通块中点的数量

每个结果占一行。

数据范围

1≤n,m≤105

输入样例:

5 5

C 1 2

Q1 1 2

Q2 1

C 2 5

Q2 5

输出样例:

Yes

2

3

来源:acwing算法基础837. 连通块中点的数量


思路(注意事项)


纯代码

#include<bits/stdc++.h>
using namespace std;

const int N = 100010;
int p[N], si[N];

int find(int x)
{
	if (p[x] != x) p[x] = find(p[x]);
	return p[x];
}
int main()
{
	int n, m;
	cin >> n >> m;

	for (int i = 1; i <= n; i++) 
	{	
		p[i] = i;
		si[i] = 1;
	}
	
	while (m --)
	{
		char c[2];
		int a, b;
		scanf("%s", c);
		
		if (c[0] == 'C') 
		{	
			scanf("%d%d", &a, &b);
			if (find(a) == find(b)) continue;
			si[find(b)] += si[find(a)];
			p[find(a)] = find(b);
		}
		else if (c[1] == '1')
		{
			scanf("%d%d", &a, &b);
			if (find(a) == find(b)) cout << "Yes" << endl;
			else cout << "No" << endl;
		}
		else {
			scanf("%d", &a);
			cout << si[find(a)] << endl;
		}
	}
    return 0; 
}

题解(带注释)

#include<bits/stdc++.h>
using namespace std;

const int N = 100010; // 定义最大节点数
int p[N]; // 并查集数组,p[i] 表示节点 i 的父节点
int si[N]; // 存储每个集合的大小,si[i] 表示以 i 为根节点的集合的大小

// 查找函数,用于查找节点 x 的根节点,并进行路径压缩
int find(int x)
{
    // 如果 x 不是根节点,递归查找其父节点的根节点,并进行路径压缩
    if (p[x] != x) p[x] = find(p[x]);
    // 返回 x 的根节点
    return p[x];
}

int main()
{
    int n, m; // n 表示节点数,m 表示操作数
    cin >> n >> m; // 输入节点数和操作数

    // 初始化并查集
    for (int i = 1; i <= n; i++) 
    {	
        p[i] = i; // 每个节点的父节点初始化为自己
        si[i] = 1; // 每个集合的大小初始化为 1
    }
    
    // 处理每个操作
    while (m --)
    {
        char c[2]; // 操作类型
        int a, b; // 操作涉及的两个节点
        scanf("%s", c); // 输入操作类型

        if (c[0] == 'C') // 如果是合并操作
        {	
            scanf("%d%d", &a, &b); // 输入要合并的两个节点
            if (find(a) == find(b)) continue; // 如果已经在同一个集合中,跳过
            si[find(b)] += si[find(a)]; // 将 a 所在集合的大小加到 b 所在集合的大小上
            p[find(a)] = find(b); // 将 a 所在集合的根节点的父节点设置为 b 所在集合的根节点
        }
        else if (c[1] == '1') // 如果是查询操作(查询两个节点是否在同一个集合中)
        {
            scanf("%d%d", &a, &b); // 输入要查询的两个节点
            if (find(a) == find(b)) cout << "Yes" << endl; // 如果在同一个集合中,输出 Yes
            else cout << "No" << endl; // 否则输出 No
        }
        else // 如果是查询操作(查询某个节点所在集合的大小)
        {
            scanf("%d", &a); // 输入要查询的节点
            cout << si[find(a)] << endl; // 输出该节点所在集合的大小
        }
    }
    return 0; 
}

相关文章:

  • 每日一题——接雨水
  • 制作安装win10系统U盘详细步骤
  • 深入解析HDFS:定义、架构、原理、应用场景及常用命令
  • 【C++并发编程实战】第1章 你好,C++的并发世界!
  • Golang语言特性
  • C语言:51单片机 常用电子元器件讲解(带英文名称)
  • Java-servlet(一)Web应用与服务端技术概念知识讲解
  • Linux top 常用参数记录
  • 扫描局域网可用端口
  • 【计算机网络入门】初学计算机网络(五)
  • 常见的 Spring 项目目录结构
  • MAC OS安装Python教程
  • C++编程指南21 - 线程detach后其注意变量的生命周期
  • JavaScript异步处理确保排序不乱的方案
  • 16981等腰三角形
  • Difyにboto3を変更したカスタムDockerイメージの構築手順
  • Java 8 新特性
  • 2024蓝桥杯省赛真题-封闭图形个数
  • 蓝桥杯备考:从记忆化搜索到动态规划
  • 深入解析 Spring WebFlux:原理与应用
  • 新华时评:网络平台“开盲盒式”扣费,“钱小”事大
  • B站一季度净亏损收窄99%:游戏营收大增76%,AI类广告收入增近4倍
  • 韩国总统选举白热化进行中,中韩青年民间交流促两国友好往来
  • 甘肃白银煤矿透水事故最新进展:3名被困矿工已无生命体征
  • “宝马女司机驾车拖行虐猫”引关注,海口警方介入调查
  • 欧洲观察室|“美国优先”使欧盟对华政策面临地缘经济困境