带权并查集(银河英雄传说)

题目链接

题目描述是中文,不再多说

本题目主要是采用带权并查集的方法去记录权值,用三个数组实现

root 数组保存根节点

size 数组保存当前根节点的最大长度

d 数组保存当前位置到根节点的距离

在查找的 a 到 b 的时候,如果 a ,b 在同一个集合,输出 a ,b 到根节点的距离的差的绝对值减一即可,如果不在同一集合输出-1

在合并的时候,因为题目说明了将 b 放到 a 后面,也就是说我们需要将 b 挂到 a 后面,也就是说要以 a 为根,更新过后,两个不相交的集合合并了,那么该集合的根节点 a 对应的最大长度就是 size[ a ] + size[ b ] ,既然是把 b 挂到 a 上面,a 到根节点的距离不变,b 到根节点的距离就是原来的 size[ a ],即 d[ b ] = size[ a ]

在 find 的函数的路径压缩过程中,·对于没被压缩的节点而言,d[a]应该是从它的根节点传递过来的,所以是d[a]  = d[a] + d[root[a]]

代码如下

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
int n;
const int maxn = 30010;
int root[maxn], size[maxn], d[maxn];
int find(int a){
	if(a == root[a])return a;
	int t = find(root[a]);
	d[a] += d[root[a]];
	return root[a] = t;
}
void mer(int a, int b){
	int fa = find(a);
	int fb = find(b);
	if(fa != fb){
		root[fb] = fa;//a is the root of the whole tree
		d[fb] = size[fa];
		size[fa] += size[fb];
	}
}
int main()
{
	for (int i = 1; i < 30010; i++){
		root[i] = i;
		size[i] = 1;
		d[i] = 0;
	}
	scanf("%d", &n);
	getchar();
	while (n--){
		char ch = getchar();
		int a, b;
		scanf("%d %d", &a, &b);
		getchar();
		if(ch == 'M'){
			mer(a, b);
		}
		else{
			if(find(a) == find(b)){
				printf("%d\n", abs(d[a] - d[b]) - 1);
			}
			else puts("-1");
		}
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值