CF1307F Cow and Vacation
先判掉 \(dis(s,t)\le k\) 的情况,现在路径一定会经过关键点。
先只考虑关键点之间可达性,显然如果关键点 \(u\) 能到关键点 \(v\),那么 \(v\) 也能到 \(u\)。于是我们只要求出连通块。
距离为 \(r\) 相当于 \(u\) 能到的是一个半径为 \(k\) 的区域,这个不是很好连边。但是有一个折半的想法,我们考虑每个点半径为 \(\frac{k}{2}\) 的区域,那么两个点可以互相到达相当于它们对应的区域相切,那么我们可以在切点处合并。这个在实现上就是从所有关键点同时 BFS \(\frac{k}{2}\) 轮,如果有两个关键点同时到达了一个点 \(x\) 就把它们合并。一个细节是 \(k\) 为奇数时不好处理,这个可以把边拆点,\(k\) 就翻倍成偶数了。
现在我们已知了关键点之间的可达性,还需要从 \(s\) 和 \(t\) 分别找第一步关键点,不妨考虑 \(s\) 的情况。这里有一个结论:取 \(p\) 为 \(s\to t\) 链上与 \(s\) 距离为 \(\frac{k}{2}\) 的点 \(q\),那么第一步取离 \(q\) 最近的关键点 \(p\) 即可。最近的关键点可以在 BFS 时求出。
这个结论的证明:如果有解,则存在一个解,设其第一步到 \(p'\),链上与 \(p'\) 距离最近点为 \(q'\),有 \(dis(s,p')\ge dis(p',q')\)。然后讨论 \(q\) 是否在 \(s\to q'\) 上,可以发现 \(dis(p,p')\le k\) 总是成立。
于是我们只要找出第一步和最后一步,然后并查集判一下即可。时间复杂度 \(O((n+q)\log n)\)。
#include <bits/stdc++.h>
using namespace std;
using pii = pair<int, int> ;
const int inf = 1e9;
const int kN = 4e5 + 5;
int n, k, r, q;
int fa[kN], jp[kN], dep[kN];
vector<int> g[kN];
void DFS(int x, int fa) {
::fa[x] = fa;
dep[x] = dep[fa] + 1;
int dif1 = dep[fa] - dep[jp[fa]];
int dif2 = dep[jp[fa]] - dep[jp[jp[fa]]];
jp[x] = (dif1 == dif2) ? jp[jp[fa]] : fa;
for(int to : g[x]) {
if(to != fa) DFS(to, x);
}
}
int KthAnc(int x, int k) {
int gl = dep[x] - k;
while(dep[x] > gl) x = (dep[jp[x]] >= gl) ? jp[x] : fa[x];
return x;
}
int LCA(int x, int y) {
if(dep[x] < dep[y]) swap(x, y);
x = KthAnc(x, dep[x] - dep[y]);
while(x != y) {
if(jp[x] != jp[y]) x = jp[x], y = jp[y];
else x = fa[x], y = fa[y];
}
return x;
}
pii nbr[kN];
bool vis[kN];
struct DSU {
int fa[kN];
DSU() { iota(fa, fa + kN, 0); }
int Find(int x) {
return (fa[x] == x) ? x : (fa[x] = Find(fa[x]));
}
void Merge(int x, int y) {
fa[Find(x)] = Find(y);
}
}dsu;
void BFS() {
queue<int> q;
for(int i = 1; i <= 2 * n; i++) nbr[i] = pii {inf, -1};
for(int i = 1; i <= r; i++) {
int x;
cin >> x;
vis[x] = 1, q.push(x);
nbr[x] = pii {0, x};
}
for(int t = 1; t <= k / 2; t++) {
int siz = q.size();
while(siz--) {
int x = q.front(); q.pop();
for(int to : g[x]) {
if(!vis[to]) {
vis[to] = 1, q.push(to);
nbr[to] = pii {t, nbr[x].second};
}else if(nbr[to].first == t) {
dsu.Merge(nbr[x].second, nbr[to].second);
}
}
}
}
}
bool Query(int s, int t) {
int lca = LCA(s, t);
int dis = dep[s] + dep[t] - 2 * dep[lca];
if(dis <= k) return 1;
auto Get = [&](int s, int t) -> int {
int anc;
if(dep[s] - dep[lca] >= k / 2) anc = KthAnc(s, k / 2);
else anc = KthAnc(t, dis - k / 2);
if(nbr[anc].first > k / 2) return -1;
return nbr[anc].second;
};
int ids, idt;
if((ids = Get(s, t)) == -1) return 0;
if((idt = Get(t, s)) == -1) return 0;
return dsu.Find(ids) == dsu.Find(idt);
}
int main() {
ios::sync_with_stdio(0), cin.tie(0);
cin >> n >> k >> r, k *= 2;
for(int i = 1; i < n; i++) {
int u, v;
cin >> u >> v;
g[u].push_back(i + n);
g[i + n].push_back(u);
g[v].push_back(i + n);
g[i + n].push_back(v);
}
DFS(1, 0), BFS();
cin >> q;
for(int i = 1; i <= q; i++) {
int s, t;
cin >> s >> t;
cout << (Query(s, t) ? "YES" : "NO") << "\n";
}
return 0;
}
浙公网安备 33010602011771号