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

传送门

题意

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

  1. ((M , i , j)),表示让第(i)号战舰所在列的全部战舰保持原有顺序,接在第(j)号战舰所在列的尾部。
  2. ((C , i , j)),表示询问第(i)号战舰与第(j)号战舰当前是否处于同一列中,如果在同一列中,它们之间间隔了多少艘战舰。

数据范围

(1 leq N leq 3 imes 10^{4})
(1 leq t leq 5 imes 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++)
#define per(i,a,n) for(int i=n-1;i>=a;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];
    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();
}
原文地址:https://www.cnblogs.com/hhyx/p/13433348.html