CF1850H The Third Letter

发布时间 2023-09-08 08:43:03作者: 空白菌

题目链接

题解

知识点:贪心,图论建模。

考虑对约束 a b d 建边 \(a \mathop{\to}\limits^d b\)\(b \mathop{\to}\limits^{-d} a\) ,这里也可以建单向边,但需要缩点,会麻烦很多。

若约束是合法的,那么遍历整张图得到的点权是不会矛盾的。因此,我们在一个连通块内任取一个点作为 \(0\) 并开始遍历整张图,访问过的点直接根据边权赋值,并标记下次不需要访问。最后,只需要检查所有约束是否得到满足即可。

时间复杂度 \(O(n)\)

空间复杂度 \(O(n)\)

代码

#include <bits/stdc++.h>
using namespace std;
using ll = long long;

vector<pair<int, int>> g[200007];
tuple<int, int, int> c[200007];

bool vis[200007];
ll val[200007];
bool dfs(int u) {
    for (auto [v, w] : g[u]) {
        if (vis[v]) continue;
        vis[v] = 1;
        val[v] = val[u] + w;
        dfs(v);
    }
    return true;
}

bool solve() {
    int n, m;
    cin >> n >> m;
    for (int i = 1;i <= n;i++) vis[i] = val[i] = 0, g[i].clear();
    for (int i = 1;i <= m;i++) {
        int u, v, d;
        cin >> u >> v >> d;
        g[u].push_back({ v,d });
        g[v].push_back({ u,-d });
        c[i] = { u,v,d };
    }

    for (int i = 1;i <= n;i++) {
        if (vis[i]) continue;
        dfs(i);
    }

    for (int i = 1;i <= m;i++) {
        auto [u, v, d] = c[i];
        if (val[v] != val[u] + d) return false;
    }
    cout << "YES" << '\n';
    return true;
}

int main() {
    std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int t = 1;
    cin >> t;
    while (t--) {
        if (!solve()) cout << "NO" << '\n';
    }
    return 0;
}