「带权并查集」银河英雄传说

银河英雄传说

原题链接:银河英雄传说

题目大意

给你N个点,然后给你两种操作,一种是合并一种是询问

题目题解

哎,加油吧

首先读题意我们就知道,这个合并到最后一定是一条链,且合并的每个过程都是一条链,合并很好做,若不考虑两点间的距离,就是简单的并查集模板,但是加上了距离之后,就是一个带权并查集了,保存两个变量,一个变量是某一点到根节点的距离,另外一个变量保存整条链的长度,前一个是用来处理查询,后一个是用来处理合并,那这个问题就很简单了 详细见代码

//#define fre yes

#include <cstdio>
#include <iostream>

const int N = 30005;
namespace Union {
    int par[N], dis[N], size[N];
    inline void init(int n) {
        for (int i = 1; i <= n; i++) {
            par[i] = i;
            size[i] = 1;
            dis[i] = 0;    
        }
    }
    
    int find(int x) {
        if(x == par[x]) return par[x];
        int t = find(par[x]);
        dis[x] += dis[par[x]];
        return par[x] = t;
    }
    
    inline void unite(int x, int y) {
        int a = find(x);
        int b = find(y);
        if(a == b) return ;
        
        par[a] = b;
        dis[a] = size[b];
        size[b] += size[a];
    }
    
    inline bool same(int x, int y) {
        return find(x) == find(y);
    }
    
    inline int solve(int x, int y) {
        find(x); find(y);
        return std::max(dis[x], dis[y]) - std::min(dis[x], dis[y]) - 1;
    }
}

int main() {
    static int T;
    scanf("%d", &T);
    Union::init(30000);
    while(T--) {
        char s[3]; int i, j;
        scanf("%s %d %d", s + 1, &i, &j);
        if(s[1] == 'M') {
            Union::unite(i, j);
        } else {
            if(Union::same(i, j)) {
                printf("%d\n", Union::solve(i, j));
            } else puts("-1");
        }
    } return 0;
}
posted @ 2019-09-23 15:57  Nicoppa  阅读(172)  评论(1编辑  收藏  举报