【ybt高效进阶3-1-3】【luogu P1196】银河英雄传说
发布日期:2021-05-07 06:59:52 浏览次数:20 分类:精选文章

本文共 1600 字,大约阅读时间需要 5 分钟。

银河英雄传说

题目链接: /

题目大意

有一些点,每次你可以把一个点所在的链的前头接在另一个点所在的链的后头上。

然后是不是会有询问,问你两个点是否连通,如果连通了它们之间隔了多少个点。

思路

那这一题问是否连通,我们自然会想到并查集。

但是它有一个东西就是要问你一个连通的链中两个点之间的距离。

那我们可以弄一个带权并查集。
什么鬼呢?其实就是不仅记录一个点在哪个连通块,还记录一些别的信息。

就不如在这道题中,我们弄两个值,一个是它到它最后的父亲的位置,一个是它这个连通块的距离。

(那因为它连通是一条链的形式存在,所以我们可以用两个在用一个连通块的点到他们最后的父亲的距离的差得出这两个点之间的距离)

那我们可以维护一下,那我们要维护到连通块父亲的距离,要怎么弄。

第一种,如果只是 find 操作,那我们可以用类似前缀和的方式,它的值就是它一级父亲的值加上它到它这个父亲的距离。
第二种,如果是 connect 操作(就是把两个点连在一起),那我们考虑怎么弄。那我们想想,连了之后在前面的就要是那个距离,但是后面的距离就加了。加了多少呢,可以想到是前面那个的大小。

所以我们就要维护连通块的大小,在 find 操作的时候就直接等于(因为你这样找到的都是在同一个连通块里面)。在 connect 操作里面就是原来两个连通块大小的和。

那就可以了。

代码

#include
using namespace std;int T, fa[30001], x, y;int num[30001], dis[30001];char c;int abss(int now) { //求绝对值 if (now < 0) return -now; return now;}int find(int now) { //并查集操作 if (fa[now] == now) return now; else { int tmp = fa[now]; fa[now] = find(fa[now]); dis[now] += dis[tmp];//距离像统计前缀和一样加上 num[now] = num[tmp];//个数就直接等于(因为是同一个连通块) return fa[now]; }}void connect(int x, int y) { int X = find(x), Y = find(y); fa[X] = Y; dis[X] = dis[Y] + num[Y];//接在后面的距离变成接在前面的距离加上前面的长度 num[Y] += num[X];//个数就是两个加起来}int main() { for (int i = 1; i <= 30000; i++) { //初始化 fa[i] = i; num[i] = 1; } scanf("%d", &T); for (int times = 1; times <= T; times++) { c = getchar(); while (c != 'M' && c != 'C') c = getchar(); if (c == 'M') { scanf("%d %d", &x, &y); connect(x, y); } else { scanf("%d %d", &x, &y); int X = find(x), Y = find(y); if (X != Y) printf("-1\n"); else { printf("%d\n", abss(dis[x] - dis[y]) - 1);//问的不是边的数量而是中间点的数量,所以要减一 } } } return 0;}
上一篇:二进制数的算术运算和逻辑运算
下一篇:数制、数的进制转换,转成b进制:除b取余、乘b取整

发表评论

最新留言

留言是一种美德,欢迎回访!
[***.207.175.100]2025年03月24日 04时45分17秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章