题目描述是中文,不再多说
本题目主要是采用带权并查集的方法去记录权值,用三个数组实现
root 数组保存根节点
size 数组保存当前根节点的最大长度
d 数组保存当前位置到根节点的距离
在查找的 a 到 b 的时候,如果 a ,b 在同一个集合,输出 a ,b 到根节点的距离的差的绝对值减一即可,如果不在同一集合输出-1
在合并的时候,因为题目说明了将 b 放到 a 后面,也就是说我们需要将 b 挂到 a 后面,也就是说要以 a 为根,更新过后,两个不相交的集合合并了,那么该集合的根节点 a 对应的最大长度就是 size[ a ] + size[ b ] ,既然是把 b 挂到 a 上面,a 到根节点的距离不变,b 到根节点的距离就是原来的 size[ a ],即 d[ b ] = size[ a ]
在 find 的函数的路径压缩过程中,·对于没被压缩的节点而言,d[a]应该是从它的根节点传递过来的,所以是d[a] = d[a] + d[root[a]]
代码如下
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
int n;
const int maxn = 30010;
int root[maxn], size[maxn], d[maxn];
int find(int a){
if(a == root[a])return a;
int t = find(root[a]);
d[a] += d[root[a]];
return root[a] = t;
}
void mer(int a, int b){
int fa = find(a);
int fb = find(b);
if(fa != fb){
root[fb] = fa;//a is the root of the whole tree
d[fb] = size[fa];
size[fa] += size[fb];
}
}
int main()
{
for (int i = 1; i < 30010; i++){
root[i] = i;
size[i] = 1;
d[i] = 0;
}
scanf("%d", &n);
getchar();
while (n--){
char ch = getchar();
int a, b;
scanf("%d %d", &a, &b);
getchar();
if(ch == 'M'){
mer(a, b);
}
else{
if(find(a) == find(b)){
printf("%d\n", abs(d[a] - d[b]) - 1);
}
else puts("-1");
}
}
return 0;
}