题意:有
n
n
艘战舰,一开始排成一行,第号战舰在第
i
i
列,两种操作:
1. 表示将第
i
i
号战舰所在的整个战舰队列,作为一个整体(头在前尾在后)接至第j号战舰所在的战舰队列的尾部。
2. 表示询问第
i
i
号战舰与第号战舰当前是否在同一列中,如果在同一列中,那么它们之间有多少战舰。
这题一看就是并查集,但怎么维护两艘战舰之间有多少战舰呢?这里就要使用带权并查集了。 val[i] v a l [ i ] 表示飞船 i i 到其所在队列队头的距离(类似一个前缀和的东西),表示以 i i <script type="math/tex" id="MathJax-Element-739">i</script>为队头的队列的飞船数量。具体说明看代码
#include<bits/stdc++.h>
using namespace std;
int val[1001000],f[1001000],num[1001000];
int find(int x)
{
if(x==f[x])
return x;
if(x!=f[x])
{
int g=f[x];
f[x]=find(f[x]);
val[x]+=val[g];//更新当前节点到根的距离
return f[x];
}
}
int merge(int x,int y)
{
int fx=find(x);
int fy=find(y);
if(fx!=fy)
{
f[fx]=fy;
val[fx]=val[fy]+num[fy];//更新合并之后fx到队头的距离
num[fy]+=num[fx];//更新以fy为队头的队列的飞船数量
num[fx]=0;//以fx为队头的队列数量清零
}
}
char s[5];
int main()
{
int t;
cin>>t;
for(int i=1;i<=35000;i++)
{
f[i]=i;
num[i]=1;
}
while(t--)
{
scanf("%s",s+1);
if(s[1]=='M')
{
int a,b;
scanf("%d%d",&a,&b);
merge(a,b);
}
if(s[1]=='C')
{
int a,b;
scanf("%d%d",&a,&b);
if(find(a)!=find(b))
cout<<"-1"<<endl;
else
cout<<abs(val[a]-val[b])-1<<endl;
}
}
return 0;
}