Loading

abc 267 f 题解

abc 267 f

题意

给定一个有 \(N\) 个结点的树,结点分别编号为 \(1, 2, \dots, N\),第 \(i\) 条边 \((1 \le i \le N - 1)\) 连接点 \(A_i, B_i\)

树上的两个结点 \(u, v\) 之间的距离定义为从 \(u\)\(v\) 的最短路径所经过的边的数量。

给定 \(Q\) 次询问,第 \(i\) 次询问给出 \(U_i, K_i\),请你输出任意一个与 \(U_i\) 距离为 \(K_i\) 的点的编号。如果不存在,输出 -1

思路

在线

首先,我们先思考这样一个问题,在什么情况下,不存在与点 \(u\) 距离为 \(k\) 的点?

当从 \(u\) 出发的最长路小于 \(k\) 时,就说明不存在这样的点。

而我们可以想到最长路这件事,就可以联想到树的直径。

令从 \(u\) 出发的最长路所到达的点为 \(v\)

可以证明,\(v\) 肯定是某一条树的直径的某一个端点,因为有一条直径的某个端点本身就是从点 \(u\) 开始的能走到的最远的点,所以 \(v\) 一定是这个搜到的点。我们设这条直径的两个端点为 \(s, t\)

所以,我们可以画一个这样的图:

也就是说,如果我们要求与 \(u\) 距离为 \(k\) 的点,就相当于在以 \(s\) 为根的树和以 \(t\) 为根的树上找 \(u\)\(k\) 级祖先。

代码

#include <bits/stdc++.h>

using namespace std;

const int N = 2e5 + 10;

int n, q, d, id[2], fa[2][20][N];
vector<int> g[N];

void dfs(int t, int f, int dis, int p) {
  if (dis > d) {
    d = dis, id[p] = t;
  }
  if (p >= 2) {
    fa[p % 2][0][t] = f;
  }
  for (int i : g[t]) {
    if (i != f) {
      dfs(i, t, dis + 1, p);
    }
  }
}

void get_fa() {
  for (int i = 0; i < 2; i++) {
    for (int j = 1; j < 20; j++) {
      for (int k = 1; k <= n; k++) {
        fa[i][j][k] = fa[i][j - 1][fa[i][j - 1][k]];
      }
    }
  }
}

int Find(int u, int k, bool p) {
  for (int i = 0; i < 20; i++, k >>= 1) {
    if (k & 1) {
      u = fa[p][i][u];
    }
  }
  return u;
}

int 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);
  }
  dfs(1, 0, 0, 0), d = 0, dfs(id[0], 0, 0, 1);
  dfs(id[0], 0, 0, 2), dfs(id[1], 0, 0, 3), get_fa();
  cin >> q;
  while (q--) {
    int u, k;
    cin >> u >> k;
    int s = max(Find(u, k, 0), Find(u, k, 1));
    cout << (!s ? -1 : s) << '\n';
  }
  return 0;
}

离线

我们可以把每个点 \(u\) 需要查询的每个 \(k\) 都记录下来,然后对树做一遍深搜,用栈来维护每一条树链的元素,记录每次询问的答案。

代码

#include <bits/stdc++.h>

using namespace std;
using pii = pair<int, int>;

const int N = 2e5 + 10;

int n, q, d, id[2], ans[N];
vector<int> g[N];
vector<pii> pos[N];
int top, stk[N];

void dfs(int t, int f, int dis, int p) {
  if (dis > d) {
    d = dis, id[p] = t;
  }
  for (int i : g[t]) {
    if (i != f) {
      dfs(i, t, dis + 1, p);
    }
  }
}

void _dfs(int t, int fa) {
  stk[++top] = t;
  for (int i : g[t]) {
    if (i != fa) {
      _dfs(i, t);
    }
  }
  for (auto [i, j] : pos[t]) {
    if (top > i) {
      ans[j] = stk[top - i];
    }
  }
  top--;
}

int 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);
  }
  dfs(1, 0, 0, 0), d = 0, dfs(id[0], 0, 0, 1);
  cin >> q;
  for (int i = 1, u, k; i <= q; i++) {
    cin >> u >> k, ans[i] = -1;
    pos[u].push_back({k, i});
  }
  _dfs(id[0], 0), _dfs(id[1], 1);
  for (int i = 1; i <= q; i++) {
    cout << ans[i] << '\n';
  }
  return 0;
}
posted @ 2023-05-17 14:45  chengning0909  阅读(48)  评论(0编辑  收藏  举报