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

题目链接:银河英雄传说

边带权并查集,舰队在合并的过程中带着它下面的舰一起走,d[x]记录战舰与fa[x]战舰之间的权值,在路径压缩的时候,

把d[x]更新为从x到树根的路径上得到所有边权之和吗,d[x]既保存了位于x之前的战舰数量。

当接收到一个Cx y指令时,分别执行get(x) ,get(y)完成查询和路径压缩。若二者返回值相同,则二者位于同一列中,输出d[x]+d[y]-1.

当接收到一个M x y指令时,把x的树根作为y树根的子节点,连接的新边的权值应该设为合并之前集合y的大小(根据题意,集合y中的全部战舰都排在集合x之前),因此我们还需要一个size数组在每个树根上记录集合大小。

#include<bits/stdc++.h>
using namespace std;
const int N = 3e4 + 5;
int fa[N], d[N], size[N];
void init()
{
    for (int i = 0; i<N; i++)
        fa[i] = i, size[i] = 1;
}
int get(int x)
{
    if (fa[x] == x) return x;
    int root = get(fa[x]);
    d[x] += d[fa[x]];
    return fa[x] = root;
}
void merge(int x, int y)
{
    x = get(x), y = get(y);
    fa[x] = y;
    d[x] = size[y];
    size[y] += size[x];
}
int main()
{
    int t;
    scanf("%d",&t);
    init();
    while (t--)
    {
        char s[2];
        int i, j;
        scanf("%s%d%d",s,&i,&j);
        if (s[0] == 'M') merge(i, j);
        else{

            if (get(i) != get(j))
                cout << -1 << endl;
            else
                cout << max(0, abs(d[i] - d[j])-1) << endl;

        }
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/xiaoguapi/p/10447377.html