对带权并查集的诠释是这样的:在对并查集进行路径压缩和合并操作时,这些权值具有一定属性,即可将他们与父节点的关系,变化为与所在树的根结点关系。

https://www.luogu.com.cn/problem/P1196

题意:一条序列,两条指令。合并指令为 M i j,含义为第 i 号战舰所在的整个战舰队列,作为一个整体(头在前尾在后)接至第 j 号战舰所在的战舰队列的尾部。询问指令:C i j。该指令意思是,询问电脑,杨威利的第 i 号战舰与第 j 号战舰当前是否在同一列中,如果在同一列中,那么它们之间布置有多少战舰。

输入输出样例

输入 #1

1
2
3
4
5
4
M 2 3
C 1 2
M 2 4
C 4 2

输出 #1

1
2
-1
1

用 dis 表示到根的距离。M i j 指令将 i 所在的根接到 j 所在队列的尾部,j 不一定是尾部(之前一直接 j …菜哭)所以需要 sum 数组记录一个队列集合的大小。dis[ fa ] += sum[ fb ] 就是合并后到根的距离。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
const int MAX=30000+10; 
int t,a,b;
char cmd;
int f[MAX],dis[MAX],sum[MAX];
int find(int x){
if(f[x]!=x){
int i=f[x];
f[x]=find(f[x]);
dis[x]+=dis[i];
sum[x]=sum[f[x]];
}
return f[x];
}
int main(){
freopen("in","r",stdin);
fi(i,0,MAX){
f[i]=i;sum[i]=1;dis[i]=0;
}
sf(t);
while(t--){
scanf("\n%c %d%d",&cmd,&a,&b);
int fa=find(a);
int fb=find(b);
if(cmd=='M'){
if(fa!=fb){
f[fa]=fb; //接到尾部 ...b 不一定是尾部
dis[fa] += sum[fb]; //更新路径
sum[fa] += sum[fb]; //更新集合大小
sum[fb] = sum[fa];
}
}else if(cmd=='C'){
if(fa!=fb){
pfc("-1\n");
}else {
pf(abs(dis[b]-dis[a])-1);
pfc("\n");
}
}
}
return 0;
}

更多:

带权并查集介绍

洛谷p2024食物链