【边带权 维护节点和根距离 两点距离】银河英雄传说
传送门
题意
初始有\(N\)艘战舰,开始每个战舰单独一列,有\(t\)条指令,每个指令可能包含两个操作
- \((M , i , j)\),表示让第\(i\)号战舰所在列的全部战舰保持原有顺序,接在第\(j\)号战舰所在列的尾部。
- \((C , i , j)\),表示询问第\(i\)号战舰与第\(j\)号战舰当前是否处于同一列中,如果在同一列中,它们之间间隔了多少艘战舰。
数据范围
\(1 \leq N \leq 3\times 10^{4}\)
\(1 \leq t \leq 5\times 10^{5}\)
题解
-
维护当前的集合的大小\(sz\),\(d\)表示当前点到树根的距离
- 到根的距离需要在查询时维护如果到根的距离,当前节点到根部的距离未被更新过时,就累加原祖先到根部的距离
-
求得是两点之间的间隔,间隔即两个点中间有几个点,中间的点不包括这条路径的起点和终点
- 每次询问间隔时候两个到根距离的差的绝对值\(-1\)就是间隔了多少个
Code
#include <bits/stdc++.h>
using namespace std;
#define rep(i, a, n) for(int i = a; i < n; i ++)
const int N = 3e5 + 10;
int fa[N], sz[N], d[N];
int _;
int find(int x) {
if(fa[x] == x) return x;
int root = find(fa[x]);
d[x] += d[fa[x]];
return fa[x] = root;
}
void merge(int a, int b) {
int pa = find(a), pb = find(b);
d[pa] = sz[pb]; // 边等于点 - 1
sz[pb] += sz[pa];
fa[pa] = pb;
}
void solve() {
char op[2];
int x, y; cin>>op>>x>>y;
if(op[0] == 'M') merge(x, y);
else {
int pa = find(x), pb = find(y);
if(pa == pb)
cout<<abs(d[x] - d[y]) - 1<<endl;
else
cout<<"-1"<<endl;
}
}
int main() {
cin>>_;
rep(i, 1, N) fa[i] = i, sz[i] = 1,d[i] = 0;
while(_ --) solve();
}