题目链接:https://www.luogu.com.cn/problem/CF1304E
这道题稍微想了一下就有思路了。
让我们先来简化一下问题,如果没有加边,仅仅是询问的话,那么该怎么做呢。
很明显在两点树上的路径只有一条,那么我们很容易求出u和v的距离dis(u, v)又因为可以来回走,所以就是问dis(u, v) + 2x 是否能 == k
那么这个问题其实就是问dis(u, v) - k 能否被2整除
现在我们考虑加边的情况。加上了一条边其实有三种情况(我想的不是很周到漏掉了第三种
1. 不通过加边 求dis(u, v) + 2x 是否能 == k
2. 通过加边 求dis(u, x) + dis(y, v) + 2x 是否能 == k
3. 通过加边 求dis(u, y) + dis(x, v) + 2x 是否能 == k
同时注意不要大于k就行
需要会LCA基础知识(这里用得是倍增LCA
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 2e6 + 10; int n, m; vector<int> G[maxn]; int dep[maxn], lg[maxn]; int f[maxn][32]; void BFS(int x) { queue<int> q; q.push(x); dep[x] = 1; while (q.size()) { int u = q.front(); q.pop(); for (auto v : G[u]) { if (dep[v]) continue; dep[v] = dep[u] + 1; f[v][0] = u; q.push(v); for (int j = 1; j <= lg[dep[v]]; ++ j) { f[v][j] = f[f[v][j-1]][j-1]; } } } } int LCA(int u, int v) { if (dep[u] < dep[v]) swap(u, v); ///根据差距倍增上跳 while (dep[u] > dep[v]) u = f[u][ lg[dep[u] - dep[v]] - 1]; if (u == v) return u; for (int i = lg[dep[u]] - 1; i >= 0; -- i) { if (f[u][i] != f[v][i]) u = f[u][i], v = f[v][i]; } return f[u][0]; } void init() { for (int i = 1; i <= n; ++ i) lg[i] = lg[i-1] + (1 << lg[i-1] == i); } int query(int u, int v) { int _lca = LCA(u, v); //cout << _lca << endl; return dep[u] + dep[v] - 2 * dep[_lca]; } int main() { scanf("%d", &n); for (int i = 1; i <= n-1; ++ i) { int u, v; scanf("%d%d", &u, &v); G[u].push_back(v); G[v].push_back(u); } init(); BFS(1); scanf("%d", &m); while (m--) { int x, y, u, v, k; scanf("%d%d%d%d%d", &x, &y, &u, &v, &k); int flag = 0; ///u - v int ans1 = query(u, v); if (ans1 <= k && (k - ans1) % 2 == 0) { flag = 1; } ///u - x - y - v int ans2 = query(u, x) + query(y, v) + 1; if (ans2 <= k && (k - ans2) % 2 == 0) { flag = 1; } ///u - y - x - v int ans3 = query(u, y) + query(x, v) + 1; if (ans3 <= k && (k - ans3) % 2 == 0) { flag = 1; } //cout << ans1 << " " << ans2 << " " << ans3 << endl; if (flag) puts("YES"); else puts("NO"); } return 0; }