P1196 [NOI2002] 银河英雄传说

题面:

指令 M : 合并两个集合
指令 C : 查询两个点之间的布置了多少战舰


算法1

(带权并查集)

0.为何使用带权并查集?

维护边权,这里指的边权时该点到根节点之间一共有多少个节点

1.带权并查集维护点到跟的距离

2.需要开两个数组存放该点到跟节点的距离,以及该集合的大小(集合中存放的元素个数)

3.路径压缩的同时,更新距离

如何更新距离:我到父节点的距离 + 父节点到根节点的距离;

4.如何进行合并操作:

(1) x集合合并到y的集合当中

(2)用y集合的大小,更新x到根节点的距离;

(3)再更新y集合的大小,原来y集合的大小 += x集合的大小

5.如何判断两点之间有多少个战舰

首先判断两点是否处于同一个集合中,如果不属于同一个集合则输出 "-1";

否则,两个点到根节点的距离的差值取绝对值 - 1

C++ 代码

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

const int N = 5e5 + 10;

int n;
int p[N],siz[N],dis[N];

int find(int x){
	if(x != p[x]) 
	{
		int fu = find(p[x]);  //先找根节点
		dis[x] += dis[p[x]];  // 我到父节点的距离 + 父节点到根节点的距离
		p[x] = fu; 
	 } 
	return p[x];
}
int main(){
	cin >> n;
	
	for(int i=1;i<=n;i++){
		p[i] = i;
		siz[i] = 1;  //每个集合的大小为 1,只有自己 
		dis[i] = 0;  //自己到自己的距离为 0 
	}
	
	while(n--){
		char op;
		int a,b;
		cin >> op >> a >> b;
		int fa = find(a), fb = find(b);
		if(op == 'M')  //合并操作 
		{
			p[fa] = fb;   //集合a 合并到集合 b
			dis[fa] = siz[fb];   //a到根节点的距离为 b集合的元素个数
			siz[fb] += siz[fa];  //b集合的元素 += a集合的元素 
		}
		else{
			if(fa != fb) cout << "-1" <<endl;
			else cout << abs(dis[a]-dis[b])-1 << endl;
		} 
	} 
	 return 0;
}

posted @   LTphy  阅读(12)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示