ybtoj并查集例题3银河英雄传说

Posted SSL_ZZL

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ybtoj并查集例题3银河英雄传说相关的知识,希望对你有一定的参考价值。

【例题3】银河英雄传说


Link

传送门
题目


解题思路

n u m [ i ] num[i] num[i]为 i为头的队伍有多少个点(就是代表一个集合里有多少点,因为i打头,所以i就为i集合的标记)
d i s [ i ] dis[i] dis[i]为 i到 f a [ i ] fa[i] fa[i](即i的父节点)有多少士兵
并查集时,需维护 d i s [ ] dis[] dis[]
这就是带边权并查集 (吧)


Code

#include <iostream>
#include <cstdio>
#include <cmath>

using namespace std;

int n, x, y, xx, yy, fa[30010], num[30010], dis[30010];
char c; 

int find(int x) {
	if (fa[x] == x)
		return x;
	int cnt = find(fa[x]);
	dis[x] = dis[fa[x]] + dis[x];  //到新父亲的距离 = 到原父亲的距离 + 原父亲到 原父亲的父亲(也就是新父亲)的距离
	fa[x] = cnt;
	return fa[x];
}

int main() {
	for (int i = 1; i <= 30000; i++)
		fa[i] = i, num[i] = 1;
	scanf("%d", &n);
	for (int i = 1; i <= n; i++) {
		cin >> c;
		scanf("%d %d", &x, &y);
		xx = find(x), yy = find(y);
		if (c == 'M') {
			fa[xx] = yy;
			dis[xx] = num[yy];  //xx接到yy的队伍后,显而易见,xx到yy之间的士兵,就是yy原来后面有多少士兵
			num[yy] += num[xx], num[xx] = 0;  //依然显而易见;ps:因为xx不是头,所以xx无法作为此集合的标记
		} else {
			if (xx != yy) 
				printf("-1\\n");
			else 
				printf("%d\\n", abs(dis[x] - dis[y]) - 1);  //还是很显而易见吧(*^▽^*)
		}
	}
}

以上是关于ybtoj并查集例题3银河英雄传说的主要内容,如果未能解决你的问题,请参考以下文章

[luoguP1196] 银河英雄传说(并查集)

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

银河英雄传说 - 带权并查集

luogu1196 银河英雄传说 (并查集)

并查集银河英雄传说

238. 银河英雄传说边带权的并查集