旅行 :题解

文章介绍了如何利用带权DisjointSetUnion(DSU)解决图论问题,特别是处理正环、负环以及不在同一连通块的查询。当存在正环或负环时,查询结果为inf;否则,输出路径上的边权。代码实现中,通过标记根节点来处理环的影响,并在查询时判断连通块是否包含环来决定输出结果。
摘要由CSDN通过智能技术生成

简单读题后,我(蒟蒻)读出了这些信息:

1.不在一个连通块的查询直接输出nan

2.连通块中如果有正环或负环,那么在这个连通块的查询答案都是inf

3.如果不是以上两种情况,就输出他们一路上的边权。

所以我想到了DSU。

由于还要处理边权,所以自然而然的想到了带权DSU。

显然,环的出现源于同个DSU的连边。

但环可以分成两种:零环/非零环(需要处理成inf)。

零环显然对答案没影响,不需要考虑。

(如果画个图可能更清晰,但我较懒,所以听评讲吧)

非零环显然会将整个DSU中的查询变为inf,所以直接标记根节点,表示本DSU需要输出inf。

于是就100pts了。

除去调代码(可能是我码力太差了)比较久外,其他还是很好想的。

#include <bits/stdc++.h>
#define int long long
using namespace std;
int n, m, q;
int p[200005];
int d[200005];
int find(int x) {
    if (x == p[x])
        return x;
    else {
        int t = p[x];
        p[x] = find(p[x]);
        d[x] += d[t];
        return p[x];
    }
}
int inf[200005];
signed main() {
    scanf("%lld%lld%lld", &n, &m, &q);
    for (int i = 1; i <= n; i++) p[i] = i, d[i] = 0;
    for (int i = 1; i <= m; i++) {
        int a, b, c;
        scanf("%lld%lld%lld", &a, &b, &c);
        int u = find(a);
        int v = find(b);
        if (u == v) {
            if (c == d[a] - d[b])
                continue;
            else
                inf[u] = 1;
        } else if (u < v) {
            p[u] = v;
            d[u] = c + d[b] - d[a];
            if (inf[u])
                inf[v] = 1;
        } else {
            p[v] = u;
            d[v] = -c + d[a] - d[b];
            if (inf[v])
                inf[u] = v;
        }
    }
    for (int i = 1; i <= q; i++) {
        int a, b;
        scanf("%lld%lld", &a, &b);
        int u = find(a), v = find(b);
        if (u != v)
            printf("nan\n");
        else {
            if (inf[u])
                printf("inf\n");
            else
                printf("%lld\n", d[a] - d[b]);
        }
    }
    return 0;
}

终于出现了一次D题能被我切掉的期末考了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值