【边带权 维护节点和根距离 两点距离】银河英雄传说

传送门

题意

初始有\(N\)艘战舰,开始每个战舰单独一列,有\(t\)条指令,每个指令可能包含两个操作

  1. \((M , i , j)\),表示让第\(i\)号战舰所在列的全部战舰保持原有顺序,接在第\(j\)号战舰所在列的尾部。
  2. \((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();
}
posted @ 2020-08-04 15:04  Hyx'  阅读(109)  评论(0编辑  收藏  举报