【牛客】并查集-Professional Manager(题解+学习笔记)

https://ac.nowcoder.com/acm/problem/15696

今天莫名奇妙被这题卡了好久,后来想想确实题解还是有我需要学习的地方。
一开始用的暴力枚举TLE了,不过也在意料之中。
但是第一遍的代码是超时在记录每株树的元素个数,第一次是用遍历的方法来更新,时间复杂度是O(n^2),一定超时。
而且观察题目,感觉只能从这里下手。
于是可以只储存每株树根的元素个数。但是这个的难点在于删除结点时,如果删除的是根结点,会比较难操作。
我们用一个新数组来记录结点的【下标】,它默认为结点一开始的序号,但是中途会有从树中移除的,就给他一个新的序号,从n+1开始给,逐渐添加,
所以我们合并的不是结点本身,而是他的下标。具体看代码。

#include<bits/stdc++.h>
using namespace std;
const int maxx=200010;
int par[maxx];
int num[maxx];//在根上记录结点个数
int id[maxx];//储存下标
int find(int x){//找根
	if(x==par[x])return x;
	return par[x]=find(par[x]);
}
int main(){
	int t; cin>>t;
	int cnt=1;
	while(t--){
		printf("Case #%d:\n",cnt++);
		int n,q; cin>>n>>q;
		for(int i=1;i<maxx;i++){//初始化
			par[i]=id[i]=i;
			num[i]=1;
		}
		int x,u,v;
		for(int i=0;i<q;i++){
			cin>>x;
			if(x==1){
				cin>>u>>v;
				int root_u=find(id[u]);//查找的是id[]而不是下标了
				int root_v=find(id[v]);
				if(root_u!=root_v){//并查集
					par[root_u]=root_v;
					num[root_v]+=num[root_u];//顺序不能反,父亲结点继承子结点的num值
				}
			}else if(x==2){
				cin>>u;
				int root_u=find(id[u]);
				num[root_u]--;//该根要少一个结点了
				id[u]=++n;//给一个新的下标
			}else if(x==3){
				cin>>u;
				int root_u=find(id[u]);
				cout<<num[root_u]<<endl;
			}else{
				cin>>u>>v;
				if(find(id[u])==find(id[v]))cout<<"YES\n";
				else cout<<"NO\n";
			}
		}
	}
	return 0;
}
posted @   Time_Limit_Exceeded  阅读(126)  评论(0编辑  收藏  举报
编辑推荐:
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!

阅读目录(Content)

此页目录为空

点击右上角即可分享
微信分享提示