并查集(二)(P1196 [NOI2002]银河英雄传说)

并查集(二)

题目要求

输入n对应n个样例

一共30000支舰队要求做两个命令

M 合 并 , C 查 询 M_{合并},C_{查询} MC

查询的是两件队之间隔了多少其他舰队

不 知 道 合 并 的 道 理 是 什 么 为 什 么 是 m e r g e ( a , b ) 就 是 把 a 放 在 b 队 列 的 末 尾 , 但 是 还 是 随 缘 做 了 不知道合并的道理是什么为什么是merge(a,b)就是把a放在b队列的末尾,但是还是随缘做了 merge(a,b)ab,

合并不输出消息,查询若两舰队再一个舰队中就输出他们的距离,反之不在一起就输出-1

用了些并查集的边权,其实就是每次模拟的时候多加一些属性

不像普通的并查集用fa[N]这里计入了三个数组维持更新信息

fa[] 指向父节点的数组

size[] 描述当前集合大小的数组

d[] 描述与根节点的距离

最后答案就是 a n s ( d [ a ] − d [ b ] ) − 1 ans(d[a] - d[b]) - 1 ans(d[a]d[b])1

代码:

#include<bits/stdc++.h>
using namespace std;
const int N = 30010; 

int fa[N], d[N], size[N];
char F;
int n, A, B;

int get(int x){
	if(fa[x] == x)
		return x;
	int root = fa[x]; 
	//路径压缩
	fa[x] = get(fa[x]);
	//更新节点到根节点的距离
	d[x] += d[root];
	size[x] = size[fa[x]];
	return fa[x]; 
}

void merge(int x, int y){
	//查询父节点再连接 
	x = get(x); 
	y = get(y);
	fa[x] = y;	//x的父节点指向y 
	d[x] += (size[y] + d[y]);//x链接到y时前面就会多一个 y的舰队的大小
	size[x] += size[y]; //y的大小也要改变 
	size[y] = size[x];
}

int main(){
	// 预处理 fa	为指向根节点的数组初始化为自己 
	// 预处理 d 	为描述该队列向根节点连线的边权初始化为0 
	// 预处理 size 	为描述每个队列的大小(初始化为1)以便于连接时计算前方边权的累加 
	for(int  i = 1; i <= 30000; i++)
	{
		fa[i] = i;
		d[i] = 0;
		size[i] = 1; 
	}
	
	
	cin >> n;
	while(n--){
		cin >> F >> A >> B;
		if(F == 'M'){	//M代表合并的标志 
			 //如果在一条队列上不进行合并
			if(get(A) != get(B))
				merge(A, B); 			 
		}else if(F == 'C'){		//查询
			//如果不在一个队列输出-1,反之输出中间隔了多少个战舰
			//       -1  /   abs(d(A) - d(B)) - 1
			if(get(A) == get(B))
				cout << abs(d[A] - d[B]) - 1 << endl;
			else
				cout << -1 << endl;		
		} 
		 
		 	
	} 
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

数学小牛马

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值