银河英雄传说
原题链接:银河英雄传说
题目大意
给你N个点,然后给你两种操作,一种是合并一种是询问
题目题解
哎,加油吧
首先读题意我们就知道,这个合并到最后一定是一条链,且合并的每个过程都是一条链,合并很好做,若不考虑两点间的距离,就是简单的并查集模板,但是加上了距离之后,就是一个带权并查集了,保存两个变量,一个变量是某一点到根节点的距离,另外一个变量保存整条链的长度,前一个是用来处理查询,后一个是用来处理合并,那这个问题就很简单了 详细见代码
//#define fre yes
#include <cstdio>
#include <iostream>
const int N = 30005;
namespace Union {
int par[N], dis[N], size[N];
inline void init(int n) {
for (int i = 1; i <= n; i++) {
par[i] = i;
size[i] = 1;
dis[i] = 0;
}
}
int find(int x) {
if(x == par[x]) return par[x];
int t = find(par[x]);
dis[x] += dis[par[x]];
return par[x] = t;
}
inline void unite(int x, int y) {
int a = find(x);
int b = find(y);
if(a == b) return ;
par[a] = b;
dis[a] = size[b];
size[b] += size[a];
}
inline bool same(int x, int y) {
return find(x) == find(y);
}
inline int solve(int x, int y) {
find(x); find(y);
return std::max(dis[x], dis[y]) - std::min(dis[x], dis[y]) - 1;
}
}
int main() {
static int T;
scanf("%d", &T);
Union::init(30000);
while(T--) {
char s[3]; int i, j;
scanf("%s %d %d", s + 1, &i, &j);
if(s[1] == 'M') {
Union::unite(i, j);
} else {
if(Union::same(i, j)) {
printf("%d
", Union::solve(i, j));
} else puts("-1");
}
} return 0;
}