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;
}