【NOI2002】银河英雄传说

这是一道带权并查集的题目。

我们维护三个数组,f[x]表示节点x所在集合的代表元素(相当于合并之后的树根),size[x]表示以x为代表元素的集合的大小是多少(相当于一列战舰的数量),d[x]表示在这一列战舰中,x前面的战舰有多少。

因此对于每一次询问,答案就是|d[x]-d[y]|-1.

我们怎样维护这三个数组呢?其中第一个数组的维护很简单,就是并查集的维护,我们重点考虑后两个数组的维护。

在路径压缩时,在把x直接指向树根的同时,我们把d[x]更新为x到树根的距离,这样我们在并查集的find函数中就可以维护d,

而对于size的维护,我们在合并时直接将前一段战舰所在的size加上后一段的size即可。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 #include <cmath>
 6 using namespace std;
 7 int t;
 8 int f[30010],size[30010],d[300010];
 9 int find(int x) {
10     if(f[x]==x) return x;
11     int xx=find(f[x]);
12     d[x]+=d[f[x]];
13     return f[x]=xx;
14 }
15 int main() {
16     cin>>t;
17     for(int i=1;i<=30000;i++) {
18         size[i]=1;
19         f[i]=i;
20         d[i]=0;
21     }
22     while(t--) {
23         char c;
24         int x,y;
25         cin>>c>>x>>y;
26         int fx=find(x);
27         int fy=find(y);
28         if(c=='M') {
29             f[fx]=fy;
30             d[fx]=size[fy];
31             size[fy]+=size[fx];
32         }
33         else {
34             if(f[x]!=f[y]) puts("-1");
35             else printf("%d
",abs(d[x]-d[y])-1);
36         }
37     }
38     return 0;
39 }
AC Code
原文地址:https://www.cnblogs.com/shl-blog/p/10803705.html