洛谷 P1196 [NOI2002]银河英雄传说

Posted 俺是小程

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了洛谷 P1196 [NOI2002]银河英雄传说相关的知识,希望对你有一定的参考价值。

有很多人都把这道题讲得很详细了,我就不再重复了。

要总结的是,这可以看作一种“边带权”的并查集,对于这种并查集我们可以另开数组记录边上的关系,然后在find和unite的同时对关系进行维护。

于是此题中我们用一个 d 数组来记录当前战舰 到 这列战舰最前面的战舰 的战舰数量,

用一个 size 数组(在程序中为了避免关键字换成了siz)记录当前战舰后面跟了多少战舰(为了方便M操作时更新d)。

具体的维护方式参考代码。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int MAXT = 5e5 + 20;
 4 const int MAXN = 3e4 + 20;
 5 
 6 namespace ufs
 7 {
 8     int fa[MAXN], d[MAXN], siz[MAXN];
 9 
10     void init()
11     {
12         for(int i = 1; i <= MAXN; i++)
13             fa[i] = i, siz[i] = 1;
14     }
15 
16     int get(int x)
17     {
18         if(x == fa[x]) return x;
19         int root = get(fa[x]);
20         d[x] += d[fa[x]];
21         return fa[x] = root;
22     }
23 
24     inline void unite(int x, int y)
25     {
26         x = get(x), y = get(y);
27         fa[x] = y, d[x] = siz[y];
28         siz[y] += siz[x];
29     }
30 }
31 
32 
33 int main()
34 {
35     //freopen("p1196.txt", "r", stdin);
36     int T;
37     cin>>T;
38     using namespace ufs;
39     init();
40 
41     char opt;int i, j;
42     while(T--)
43     {
44         scanf(" %c ", &opt);
45         if(opt == M)
46         {
47             scanf("%d%d", &i, &j);
48             unite(i, j);
49         }
50         else
51         {
52             scanf("%d%d", &i, &j);
53             if(get(i) != get(j)) puts("-1");
54             else printf("%d\n", abs(d[i] - d[j]) - 1);
55         }
56     }
57     return 0;
58 }

注意有个细节:别忘了d[ x ]保存位于 x 之前的战舰数量,d[ y ]保存位于 y 之前的战舰数量,所以x,y之间的战舰数量应该是两者之差的绝对值减1。

以上是关于洛谷 P1196 [NOI2002]银河英雄传说的主要内容,如果未能解决你的问题,请参考以下文章

[洛谷P1196][NOI2002]银河英雄传说 - 带偏移量的并查集

做题记录:P1196 [NOI2002]银河英雄传说

P1196 [NOI2002] 银河英雄传说(并查集)

P1196 [NOI2002]银河英雄传说

P1196 [NOI2002]银河英雄传说

NOI2002 银河英雄传说(luogu p1196)