【C++】洛谷 P3367 【模板】并查集

后续

我改动的地方没什么实际意义,原因的话原博主在评论区详细说明了。请直接参考原始代码


参考

洛谷 P3367 【模板】并查集

代码参考全网最通俗易懂并查集讲解

部分改动声明

自认为代码有少许瑕疵,更改了小部分,用“//补充”标记出来了,欢迎大家批评指正

代码

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

/*
  洛谷 P3367 【模板】并查集
  https://www.luogu.com.cn/problem/P3367
  
  代码参考全网最易懂并查集讲解:
  https://blog.csdn.net/the_ZED/article/details/105126583
  
  自认为代码有少许瑕疵,更改了小部分,用“//补充”标记出来了,欢迎大家批评指正
 */
const int SIZE=1e4+10;				//指定并查集所能包含元素的个数(由题意决定)
int pre[SIZE];     					//存储每个结点的前驱结点 
//补充
//由于命名冲突,rank改成了rankIndex
int rankIndex[SIZE];    			//树的高度,注意树的高度主要与某个集合的根父节点有关
void init(int n)     				//初始化函数,对录入的 n个结点进行初始化 
{
    
    
	//补充
	for(int i = 1; i <= n; i++){
    
    	//针对下标从1开始的情况
		pre[i] = i;     			//每个结点的上级都是自己 
		rankIndex[i] = 1;    		//每个结点构成的树的高度为 1 
	} 
}
/*
int find(int x)     	 		    //查找结点 x的根结点 
{
	if(pre[x] == x) return x;  		//递归出口:x的上级为 x本身,则 x为根结点 
	return find(pre[x]); 			//递归查找 
} 
*/
// 在查找根节点的同时完成路径压缩
int find(int x)     				//改进查找算法:完成路径压缩,将 x的上级直接变为根结点,那么树的高度就会大大降低 
{
    
    
	if(pre[x] == x) return x;		//递归出口:x的上级为 x本身,即 x为根结点 
	/*
	改得没意义
	//补充
	if(rankIndex[x]>2){				//路径压缩:将所有高度大于2的节点全部转换为高度为2的节点
		rankIndex[x]=2;
	}
	*/
	return pre[x] = find(pre[x]);   //此代码相当于先找到根结点 rootx,然后 pre[x]=rootx 
} 

bool isSame(int x, int y)      		//判断两个结点是否连通 
{
    
    
	return find(x) == find(y);  	//判断两个结点的根结点(即代表元)是否相同 
}

//补充:
//疑惑:在合并不同集合的节点时,如果节点x作为某节点的子节点,那么,以节点x为父节点的节点以及节点x都要增加rankIndex的值
//缺点:这个步骤复杂度为O(n),会超时
//解答:由于rankIndex集合主要与某个集合的根父节点有关,下面各个节点的rankIndex可以不用管,
//而每次在 调用改进find方法 时,rankIndex的大小都会被更新,
//rankIndex的范围都在1~2之间,因此每次各个要合并的子集的高度都为1~2之间。
//因此,调用改进find方法 rankIndex 大小比较无需更新其子节点的rankIndex

bool join(int x,int y)
{
    
    
	x = find(x);						//寻找 x的代表元
	y = find(y);						//寻找 y的代表元
	if(x == y) return false;			//如果 x和 y的代表元一致,说明他们共属同一集合,则不需要合并,返回 false,表示合并失败;否则,执行下面的逻辑
	if(rankIndex[x] > rankIndex[y]) 
		pre[y]=x;						//如果 x的高度大于 y,则令 y的上级为 x (为了减少各个子树之间的高度相对差)
	else								//否则
	{
    
    
		if(rankIndex[x]==rankIndex[y]) 
			rankIndex[y]++;				//如果 x的高度和 y的高度相同,则令 y的高度加1
		pre[x]=y;						//让 x的上级为 y
	}
	return true;						//返回 true,表示合并成功
}

void read(){
    
    
	int z,x,y,//操作,每次操作的两个元素
	n,//元素个数
	m;//操作个数
	cin>>n>>m;
	init(n);
	for(int i=0;i<m;i++){
    
    
		cin>>z>>x>>y;
		if(z==1){
    
    
			join(x,y);
		}else{
    
    
			bool isSameGroup=isSame(x,y);
			cout<<(isSameGroup?"Y":"N")<<endl;
		}
	}
}

int main() {
    
    
	read();
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_33843237/article/details/129568687