首页 > 其他分享 >AcWing 836. 合并集合

AcWing 836. 合并集合

时间:2023-12-04 15:25:26浏览次数:29  
标签:836 int 元素 find 编号 集合 节点 AcWing

题面:
一共有 \(n\) 个数,编号是 \(1∼n\),最开始每个数各自在一个集合中。
现在要进行 \(m\) 个操作,操作共有两种:
1、M a b,将编号为 \(a\) 和 \(b\) 的两个数所在的集合合并,如果两个数已经在同一个集合中,则忽略操作;
2、Q a b,询问编号为 \(a\) 和 \(b\) 的两个数是否在同一个集合中;

原题链接:836. 合并集合 - AcWing

并查集

对lareges大佬的笔记的再总结,自用学习,感谢大佬
原文非常清晰明了,膜拜:下班前几分钟,我彻底弄懂了并查集

  • 并查集(Union Find),也叫「不相交集合(Disjoint Set)」,
    顾名思义,它专门用于动态处理不相交集合的「合」与「询」问题。
  • 并查集的两种操作
    • 合并:合并两个元素所属集合;
    • 查询:查询某个元素所属集合。这可以用于判断两个元素是否属于同一集合
  • parent 数组
    • p[i] 表示编号为 i 的节点的父节点的编号。
    • 特别地,定义根节点的父节点是其自身。
    • 代表元法:把每个集合看成一棵,节点元素一一对应,根节点称为该集合的代表元
      • 树的根节点的编号为整个树(集合)的编号,
        对于任一元素 \(x\),可以自底向上追溯到根节点,来判断它属于哪个集合。
      • 设计理念:三个不重要
        • 谁作为根节点不重要:根节点与非根节点只是位置不同,并没有附加的含义;
        • 树怎么形成的不重要:合并的时候任何一个集合的根节点指向另一个集合的根节点就可以;
        • 树的形态不重要:理由同「谁作为根节点不重要」。
    • p[] 数组的初始化
      • 根据代表元法,最初每个元素都是一棵树;
      • 树中只有根节点,因此对于任一元素 \(i\) ,都有 \(p [ i ] = i\) 成立。
      • 代码:for (int i = 1; i <= n; i++) p[i] = i;
  • 查询:追溯根节点,来判断节点属于哪个集合。
    • 时间复杂度 \(O(n)\):while (p[x] != x) x = p[x];(\(n\) 为树的高度)
    • 优化方案:路径压缩
      • 从元素 \(x\) 不断追溯到根节点会形成一条路径;
      • 查询结束后,我们将该路径上除了根节点的每个节点都直接连接到根节点上;
      • 在后续的查询过程中,若查询的是该路径上的点,时间复杂度即为 \(O(1)\) 。
  • 合并:将其中一棵树的根节点指向另一棵树的根节点,从而合并两棵树。
    • 代码:p[find(a)] = find(b);
#include<bits/stdc++.h>
using namespace std;

const int N = 1e5 + 10;

int n, m, a, b;
int p[N];	//p[x]: 指向x的父节点
char op;

//返回元素x所属集合的编号
int find(int x) {
	if (p[x] != x) //如果元素x不是根节点
		p[x] = find(p[x]); //让元素x直接指向根节点
	return p[x];  //返回x的父节点的编号
}

int main()
{
	cin >> n >> m;
	for (int i = 1; i <= n; i++)  p[i] = i;
	//法二:iota(p, p + n + 1, 0);	//顺序赋值函数iota(起点,终点,起始值)
	while (m--) {
		cin >> op >> a >> b;
		if (op == 'M')
			p[find(a)] = find(b);
		else
			cout << (find(a) == find(b) ? "Yes\n" : "No\n");
	}
}

标签:836,int,元素,find,编号,集合,节点,AcWing
From: https://www.cnblogs.com/haruhomu/p/17875000.html

相关文章

  • AcWing 240. 食物链
    题面:有三类动物\(A,B,C\),\(A\)吃\(B\),\(B\)吃\(C\),\(C\)吃\(A\)。现有\(N\)个动物,以\(1∼N\)编号,每个动物都是\(A,B,C\)中的一种。用两种说法对这\(N\)个动物所构成的食物链关系进行描述:第一种说法是1XY,表示\(X\)和\(Y\)是同类。第二种说法是2X......
  • AcWing 148. 合并果子
    题面:把所有的果子合成一堆:每一次合并,可以把两堆果子合并到一起,消耗的体力等于两堆果子的重量之和。达达在合并果子时总共消耗的体力等于每次合并所耗体力之和。假定每个果子重量都为\(1\),并且已知果子的种类数和每种果子的数目,你的任务是设计出合并的次序方案,使达达耗费的体......
  • AcWing 282. 石子合并
    题面:设有 \(N\)堆石子排成一排,其编号为 \(1,2,3,…,N\),现在要将这 \(N\) 堆石子合并成为一堆。每次只能合并相邻的两堆,合并的代价为这两堆石子的质量之和。请找出一种合理的方法,使总的代价最小,输出最小代价。原题链接:282.石子合并-AcWing乍一看上去很像哈夫曼树,但并......
  • Acwing 3240. 压缩编码
    本题大意:使用01串为单词编码,要求:1、编码使用前缀码,即任何一个单词的编码不是另一个单词编码的前缀;2、编码需要按字典序升序排列,比如 \(C\) 的编码的字典序需要 \(D\) 的编码之前。请找出一种字典序编码,使得文字经过编码后的长度\(L\)最小,输出最小长度。原题链接:324......
  • AcWing 143. 最大异或对
    题面:在给定的\(N\)个整数\(A1,A2……AN\)中选出两个进行\(xor\)(异或)运算,得到的结果最大是多少?原题链接:143.最大异或对-AcWing什么是异或?1、相同为\(0\),不同为\(1\);2、\(0\)和任意数字进行异或,结果为数字本身。为什么该题采用二叉字典树?整数可以转化为32位......
  • AcWing 835. Trie字符串统计
    题面:维护一个字符串集合,支持两种操作:①Ix向集合中插入一个字符串x;②Qx询问一个字符串在集合中出现了多少次。共有\(N\)个操作,所有输入的字符串总长度不超过\(105\),字符串仅包含小写英文字母。原题链接:835.Trie字符串统计-AcWingTrie字典树[1]//输入:Idog......
  • AcWing 831. KMP字符串
    题面:给定一个字符串S,以及一个模式串P,所有字符串中只包含大小写英文字母以及阿拉伯数字。模式串P在字符串S中多次作为子串出现。求出模式串P在字符串S中所有出现的位置的起始下标。原题链接:831.KMP字符串-AcWing核心:next数组-最长相等前后缀next[i]存储......
  • AcWing 92. 递归实现指数型枚举
    题面:从\(1∼n\)这\(n\)个整数中随机选取任意多个,输出所有可能的选择方案(求子集)。原题链接:92.递归实现指数型枚举-AcWing目录:使用dfs树的解法使用二进制与状态压缩的解法1.使用dfs树的解法层级既代表递归深度也代表当前数字,左子树为选该层数字,右子树为不选。#i......
  • AcWing 842. 排列数字 && AcWing 843. n-皇后问题
    842.排列数字(全排列)题面:给定一个整数\(n\),将数字\(1∼n\)排成一排,将会有很多种排列方法。现在,请你按照字典序将所有的排列方法输出。#include<iostream>usingnamespacestd;constintN=10;intpath[N];//保存序列boolst[N];//数字是否被用过,bool类型的全局变......
  • AcWing 828. 模拟栈
    题面:实现一个栈,栈初始为空,支持四种操作:pushx–向栈顶插入一个数\(x\);pop–从栈顶弹出一个数;empty–判断栈是否为空;query–查询栈顶元素。现在要对栈进行\(M\)个操作,其中的每个操作\(3\)和操作\(4\)都要输出相应的结果。原题链接:828.模拟栈-AcWing//......