传送门
题意
初始有(N)艘战舰,开始每个战舰单独一列,有(t)条指令,每个指令可能包含两个操作
- ((M , i , j)),表示让第(i)号战舰所在列的全部战舰保持原有顺序,接在第(j)号战舰所在列的尾部。
- ((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();
}