分析:带权并查集,利用一个数组来存储每个飞船的位置,值得注意的是,当用并查集进行压缩时,需要记录队列的长度,否则你得到的只是你本身位置加上根节点的位置的长度(这里容易翻车),还有就是压缩时,位置的更新也需要注意。也是很容易出BUG的。
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn = 50010;
int fa[maxn], num[maxn];
int T;
int loc[maxn];
/*int find(int x)
{
//错误代码路径压缩时,位置更新不明确。
int r = x;
while (r != fa[r])
{
loc[r] += loc[fa[r]];
r = fa[r];
}
int i = x, j;
while (fa[i] != r)
{
loc[i] += loc[r];
j = fa[i];
fa[i] = r;
i = j;
}
return r;
}*/
int find(int x) { //查找祖先的函数
if (fa[x] == x)return fa[x];
int fn = find(fa[x]); //先递归找到祖先
loc[x] += loc[fa[x]]; //在回溯的时候更新fa(因为更新时要用到正确的fa[祖先],
//所以只能在回溯的时候更新)
return fa[x] = fn;
}
void unite(int x, int y)
{
int fx = find(x);
int fy = find(y);
if (fx != fy)
{
loc[fx] += num[fy];
fa[fx] = fy;
num[fy] += num[fx];//用num记录队列长度防止出现下面1情况。
num[fx] = num[fy];
//loc[fx] += loc[fy]+1;//合并时这样判断长度出错,这样直接加在了
//头元素后面而忽略了原有的队列长度。
find(x); find(y);
}
}
int main()
{
scanf("%d", &T);
for (int i = 0; i <= 30000; i++)
{
fa[i] = i;
num[i] = 1;
loc[i] = 0;
}
//memset(loc, 0, sizeof(loc));
for (int i = 0; i < T; i++)
{
int a, b;
char c;
cin >> c;
scanf("%d%d", &a, &b);
int fx = find(a), fy = find(b);
if (c == 'M')
{
unite(a, b);
}
else if (c == 'C') {
if (fx != fy)
{
printf("-1\n");
}
else {
int d;
d = abs(loc[a] - loc[b]);
/*if (loc[b] > loc[a])
d = loc[b] - loc[a];
else
{
d = loc[a] - loc[b];
}*/
printf("%d\n", d - 1);
}
}
}
return 0;
}