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

https://www.acwing.com/problem/content/240/

除了位于哪个集合的\(fa[i]\)之外,还要维护一个\(dis[i]\),表示该元素在当前集合的深度
路径压缩的时候,沿途更新之前合并过去的元素的\(dis\),
同时还要维护集合的大小\(sz\), 用于更新\(dis\)

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<stack>
#include<queue>
using namespace std;
typedef long long ll;

const int maxn = 30010;

int T;
int fa[maxn], dis[maxn], sz[maxn];
char s[2];

int find(int x){
	if(fa[x] == x) return x;
	int root = find(fa[x]); // 找到父节点所在的集合
	dis[x] += dis[fa[x]];  // 加上要合并过去元素当前的sz
	return fa[x] = root;
}

void unite(int x, int y){
	x = find(x), y = find(y);
	fa[x] = y; dis[x] = sz[y];
	sz[y] += sz[x];
}

ll read(){ ll s=0,f=1; char ch=getchar(); while(ch<'0' || ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0' && ch<='9'){ s=s*10+ch-'0'; ch=getchar(); } return s*f; }

int main(){
 	for(int i = 1; i <= 30000; ++i) fa[i] = i, dis[i] = 0, sz[i] = 1;
 	
	scanf("%d", &T);
	int u, v;
	for(int i = 1; i <= T ; ++i) {
		scanf("%s",s);
		scanf("%d%d", &u, &v);
		
		if(s[0] == 'M'){
			unite(u, v);
		}else{
			int fu = find(u), fv = find(v);
			if(fu != fv){
				printf("-1\n");
			}else{
				if(dis[u] < dis[v]) swap(dis[u], dis[v]);
				printf("%d\n", dis[u] - dis[v] - 1);
			}
		}
	}
	return 0;
}
posted @ 2020-11-10 20:44  Tartarus_li  阅读(54)  评论(0编辑  收藏  举报