题解:P1196 [NOI2002] 银河英雄传说
题意
给定一个操作序列,包含两种操作:
- M i j : 将 i 所在的队列合并到 j 的末尾
- C i j : 查询 i 与 j 间隙的长度
特别地,保证 M 操作时, i 与 j 不在同一个序列;C 操作时,若 i 与 j 不在同一个队列,输出 -1。
所以我们可以在find过程中按照这个方式进行路径压缩。
代码
#include <iostream>
using namespace std;
#define MAX_N 30000
int color[MAX_N + 10] = { 0 },
sz[MAX_N + 10] = { 0 },
dis[MAX_N + 10] = { 0 };
//获取 i 的颜色
int find(int i) {
int fa = color[i];
if(fa == i) return fa;
int ret = find(fa);
dis[i] = dis[i] + dis[fa];
return color[i] = ret;
}
//把 b 合并到 a 之下
void merge(int a, int b) {
int aa = find(a), bb = find(b);
if(aa == bb) return ;
//bb一定是某个根结点
dis[bb] = sz[aa];
sz[aa] += sz[bb];
color[bb] = aa;
}
int main() {
for(int x = 1; x <= MAX_N; x++) color[x] = x, sz[x] = 1;
cin.tie(0), cout.tie(0), ios::sync_with_stdio(false);
int _;
cin >> _;
while(_--) {
char op;
int i, j;
cin >> op >> i >> j;
int aa = find(i), bb = find(j);
if(op == 'M') merge(j, i);
else {
if(i == j) cout << 0 << "\n";
else if(aa != bb) cout << -1 << "\n";
else cout << max(dis[i], dis[j]) - min(dis[i], dis[j]) - 1 << "\n";
}
}
return 0;
}