G. Vlad and the Mountains
https://codeforces.com/contest/1851/problem/G
离线+并查集
首先观察路径 \(i \to j\to k\) 其必须满足如下条件:
- \(h_j-h_i\leq e\)
- \(h_k-h_j\leq e - h_j+h_i\iff h_k-h_i\leq e\)
不难发现我们的路径最后的变化量只和起点和终点的高度有关。
那么要以 \(e\) 为能量初值,从 \(a\to b\) 的一条合法的路径,必然满足经过的所有点 \(k\) 都满足 \(h_k\leq h_a+e\)。
容易想到考虑点权的并查集的 trick,想到离线处理,把询问按 \(h_a+e\) 和 点权 \(h_i\) 都从小到大排,每次加入一个满足 \(h_i\leq h_a+e\) 的点,合并所有和 \(i\) 相邻且已经加入的点的边。当 \(a,b\) 位于同一个连通块的时候,就一定存在一个满足条件的合法的路径从 \(a\to b\)。
Code
#include <bits/stdc++.h>using LL = long long;void solve() {int n, m;std::cin >> n >> m;std::vector<std::vector<int>> g(n + 1);std::vector<std::array<int, 2>> p(n + 1);for (int i = 1; i <= n; i++) {std::cin >> p[i][0];p[i][1] = i;}while (m--) {int u, v;std::cin >> u >> v;g[u].push_back(v);g[v].push_back(u);}int q;std::cin >> q;std::vector<std::array<int, 4>> qry(q + 1);std::vector<int> ans(q + 1);for (int i = 1; i <= q; i++) {int a, b, e;std::cin >> a >> b >> e;qry[i][0] = p[a][0] + e, qry[i][1] = a, qry[i][2] = b, qry[i][3] = i;}std::sort(qry.begin() + 1, qry.end());std::sort(p.begin() + 1, p.end());std::vector<int> f(n + 1);for (int i = 1; i <= n; i++) {f[i] = i;}std::function<int(int)> find = [&](int x) -> int {return x == f[x] ? x : f[x] = find(f[x]);};std::vector<bool> st(n + 1, false);auto add = [&](int u) {st[u] = true;for (auto v : g[u]) {if (st[v]) {f[find(v)] = find(u);}}};for (int i = 1, j = 1; i <= q; i++) {while (j <= n && p[j][0] <= qry[i][0]) {add(p[j++][1]);}ans[qry[i][3]] = find(qry[i][1]) == find(qry[i][2]);} for (int i = 1; i <= q; i++) {std::cout << (ans[i] ? "YES" : "NO") << '\n';}
}int main() {std::ios::sync_with_stdio(false);std::cin.tie(nullptr);int t;std::cin >> t;while (t--) {solve();}return 0;
}