[ABC267F] Exactly K Steps 题解

发布时间 2023-12-26 21:31:35作者: MoyouSayuki

[ABC267F] Exactly K Steps 题解

思路

首先发现,如果对于查询 \((u, k), k > 0\) 可行,那么对于 \((u, k - 1)\) 也一定可行,因为往回走一步就可以了,所以对于一个点可以找到离它最远的点,根据直径的结论,这个点一定是直径的端点之一。

为了方便做,以直径的端点之一为根,然后写一个 K 级祖先稍微分讨一下就搞好了。

时间复杂度:\(O(n\log n + q\log n)\)

#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
//#define int long long

using namespace std;

const int N = 2e5 + 10;

int n, q;
vector<int> g[N];

int dist[2][N], A, B, f[N][20], dep[N];
void dfs(int dist[], int u, int fa) {
     f[u][0] = fa;
     for(int i = 1; i < 20; i ++)
          f[u][i] = f[f[u][i - 1]][i - 1];
     for(auto v : g[u]) {
          if(v == fa) continue;
          dist[v] = dist[u] + 1;
          dep[v] = dep[u] + 1;
          dfs(dist, v, u);
     }
}
int LCA(int a, int b) {
     if(dep[a] < dep[b]) swap(a, b);
     for(int i = 19; i >= 0; i --)
          if(dep[f[a][i]] >= dep[b])
               a = f[a][i];
     if(a == b) return a;
     for(int i = 19; i >= 0; i --)
          if(f[a][i] != f[b][i]) 
               a = f[a][i],
               b = f[b][i];
     return f[a][0];
}
int jump(int u, int k) {
     for(int i = 20; i >= 0; i --)
          if(k >= (1 << i)) u = f[u][i], k -= (1 << i);
     return u;
}
signed main() {
     ios::sync_with_stdio(0), cin.tie(0);
     cin >> n;
     for(int i = 1, a, b; i < n; i ++) {
          cin >> a >> b;
          g[a].push_back(b), g[b].push_back(a);
     } cin >> q;
     dfs(dist[0], 1, 1);
     for(int i = 1; i <= n; i ++) if(dist[0][i] > dist[0][A]) A = i;
     dep[A] = 0, dfs(dist[1], A, A);
     for(int i = 1; i <= n; i ++) if(dist[1][i] > dist[1][B]) B = i;
     dist[0][B] = 0;
     dfs(dist[0], B, 0), 
     dist[1][A] = 0, dep[A] = 0;
     dfs(dist[1], A, 0);
     for(int i = 1, x, y; i <= q; i ++) {
          cin >> x >> y;
          if(max(dist[0][x], dist[1][x]) < y) cout << -1 << '\n';
          else {
               if(dep[x] >= y) {
                    cout << jump(x, y) << '\n';
                    continue;
               }
               int lca = LCA(B, x);
               y -= dep[x] - dep[lca];
               cout << jump(B, dep[B] - dep[lca] - y) << '\n';
          }
     }
     return 0;
}