题目【带权并查集】
思路
- 在每次合并的时候,只要更新合并前队头到目前队头的距离就可以了
- 之后其它的就可以利用它来算出自己到队头的距离。
- 对于原来的队头,它到队头的距离为0,当将它所在的队列移到另一个队列后面时,它到队头的距离就是排在它前面的飞船数,也就是合并前的num[pa]。
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 30010;
int p[N], d[N], cnt[N];//u到顶点的距离, set u的数目
int find(int x) {
if(x != p[x]) {
int px = p[x];
p[x] = find(p[x]);
d[x] += d[px];
}
return p[x];
}
void merge(int a, int b) {
int pa=find(a), pb=find(b);
if(pa == pb) return;
//pa合到pb
p[pa] = pb;
d[pa] = cnt[pb];//pa到pb的距离为原来pb的大小(集合a直接加在集合b的后面)
cnt[pb] += cnt[pa];
}
int main()
{
int T;
cin>>T;
for(int i=0; i<N; ++i) p[i] = i, cnt[i] = 1;
while(T--) {
char op[2];
int a, b;
scanf("%s%d%d", op, &a, &b);
if(op[0] == 'M') {
merge(a,b);
}else {
//C
if(find(a) != find(b)) {
printf("-1\n");
}else {
printf("%d\n", abs(d[a]-d[b])-1);//a与b之间的数目=a到root的距离-b到root的距离-1
}
}
}
return 0;
}