G. Vlad and the Mountains
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;
}

浙公网安备 33010602011771号