题目
分析
对于M指令,一次移动整列,并且是把两列合并成一列。
对于C指令:判断飞船 i 和飞船 j 是否在同一列,若在,则输出它们中间隔了多少艘飞船。
由于需要判断是否在同一列,每列初始都只有一艘飞船,之后需要不断合并,所以很容易就想到要用并查集来实现。
AC代码
#include <iostream>
#include <cmath>
using namespace std;
int f[30001], dis[30001], num[30001];
/*
f[i]:i的祖先,即飞船前一个飞船
dis[i]:飞船与它所在列头的距离,初始为 0
num[i]:第 i 列飞船的数量,初始为 1
*/
// 初始化
void init()
{
for (int i = 1; i <= 30000; ++i)
{
f[i] = i;
dis[i] = 0;
num[i] = 1;
}
}
int find(int x)
{
if (f[x] == x)
{
return f[x];
}
int fn = find(f[x]);// 以后尽量这样写,对付带权并查集
dis[x] += dis[f[x]];// 回溯时更新
return f[x] = fn;
}
int main()
{
init();
int t;
cin >> t;
while (t--)
{
char c;
int x, y;
cin >> c >> x >> y;
int h1 = find(x);
int h2 = find(y);
if (c == 'M') {
f[h1] = h2; // h1放在h2后面
dis[h1] += num[h2];// 那么h2尾部距离列头更远
num[h2] += num[h1];// 那么h2列增加飞船数量增加
num[h1] = 0;// h1列没有飞船了
}
else
{
if (h1 != h2)
{
cout << -1 << endl;
}
else
{
cout << abs(dis[x] - dis[y]) - 1 << endl;
}
}
}
return 0;
}