并查集简述

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

两个基本操作

find操作:询问两个元素是否属于一个集合

merge操作:合并两个集合

首先,初始化p数组,一开始每一个元素都是一个集合,即每个元素的父节点都是自己

for(int i=0;i<=n;i++)p[i]=i;//每个元素都是一个集合

随后,读取元素进行上述基本操作

find操作

定义find函数返回所查询元素的父亲结点

int find(int x)//返回x的祖宗节点
{
	return find(p[x]);
}

此时可以进一步进行优化将每个子节点都指向父节点进行路径压缩,大大降低时间复杂度

int find(int x)//返回x的祖宗节点+路径压缩
{
	if(p[x]!=x)p[x]=find(p[x]);
	return p[x];
}

merge操作

合并a,b两个元素所在集合

void merge(int a,int b)
{
	p[find(a)]=find(b);
}

代码解释:将a的父亲结点赋值为b的父亲结点,也就是将a集合合并到b集合,将a的根节点接到b的根节点上

全代码:

#include<iostream>
using namespace std;
const int N=100100;
int n,m;
int p[N];
int find(int x)//返回x的祖宗节点+路径压缩
{
	if(p[x]!=x)p[x]=find(p[x]);
	return p[x];
}
void merge(int a,int b)//合并操作
{
	p[find(a)]=find(b);
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=0;i<=n;i++)p[i]=i;//每个元素都是一个集合
	while(m--)
	{
		char op[2];//读取操作
		int a,b;//读取元素
		scanf("%s%d%d",op,&a,&b);
		if(op[0]=='M')merge(a,b);
		else
		{
			if(find(a)==find(b))puts("Yes");
			else puts("No");
		}
	}
	return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值