好吧,作为一道绿题,我还是没能够自己做出来。
我做这道题时思路:利用并查集,对于 M 询问,如果不在同一集合则将两者所在集合合并,对于 C 询问
,如果不在同一集合很好解决,如果在同一集合,我们需要解决的首要问题是如何计算出两者之间的数量
。
所以就从这道题出发,学习一下带权并查集吧!
思路:通过上面的分析,我们发现,只要我们能够计算两者之间的距离,这道题便迎刃而解,那么该如何
维护呢? 我们可以修改 find 函数,在每一次递推中,更新当前集合的大小,同时更新顶部节点到当前
节点的距离,最后只要算两个节点的距离差就可以了。
AC代码:
点击查看代码
#include<bits/stdc++.h>
using namespace std;
int fa[30005],s[30001],d[30001];//fa表示每个节点的父亲,s表示当前节点到根的距离,d表示当前所在集合的大小
int find(int x)
{
if(x==fa[x])return x;
else
{
int k=fa[x];
fa[x]=find(fa[x]);
s[x]+=s[k];
d[x]=d[fa[x]];
return fa[x];
}
}
int main()
{
for(int i=1;i<=30000;i++)
{
fa[i]=i;
s[i]=0;//初始到根的距离都为0
d[i]=1;//初始每个集合大小都为1
}
int t;
cin>>t;
while(t--)
{
char op;
cin>>op;
if(op=='M')
{
int a,b;
cin>>a>>b;
int aa=find(a),bb=find(b);
fa[aa]=bb;//把 i 放在 j 后面
s[aa]+=d[bb];//更新节点到根的距离
d[aa]+=d[bb];//更新所在集合大小
d[bb]=d[aa];
}
else if(op=='C')
{
int a,b;
cin>>a>>b;
int aa=find(a),bb=find(b);
if(aa!=bb)
{
cout<<-1<<endl;
}
else
{
cout<<abs(s[a]-s[b])-1<<endl;
}
}
}
return 0;
}