G. Sakurako and Chefir

onlyblues發表於2024-10-25

G. Sakurako and Chefir

Given a tree with $n$ vertices rooted at vertex $1$. While walking through it with her cat Chefir, Sakurako got distracted, and Chefir ran away.

To help Sakurako, Kosuke recorded his $q$ guesses. In the $i$-th guess, he assumes that Chefir got lost at vertex $v_i$ and had $k_i$ stamina.

Also, for each guess, Kosuke assumes that Chefir could move along the edges an arbitrary number of times:

from vertex $a$ to vertex $b$, if $a$ is an ancestor$^{\text{∗}}$ of $b$, the stamina will not change;

from vertex $a$ to vertex $b$, if $a$ is not an ancestor of $b$, then Chefir's stamina decreases by $1$.

If Chefir's stamina is $0$, he cannot make a move of the second type.

For each assumption, your task is to find the distance to the farthest vertex that Chefir could reach from vertex $v_i$, having $k_i$ stamina.

$^{\text{∗}}$Vertex $a$ is an ancestor of vertex $b$ if the shortest path from $b$ to the root passes through $a$.

Input

The first line contains a single integer $t$ ($1\le t\le 10^4$) — the number of test cases.

Each test case is described as follows:

  • The first line contains a single integer $n$ ($2 \le n \le 2 \cdot 10^5$) — the number of vertices in the tree.
  • The next $n-1$ lines contain the edges of the tree. It is guaranteed that the given edges form a tree.
  • The next line consists of a single integer $q$ $(1\le q\le 2 \cdot 10^5)$, which denotes the number of guesses made by Kosuke.
  • The next $q$ lines describe the guesses made by Kosuke, with two integers $v_i$, $k_i$ $(1\le v_i \le n, 0 \le k_i\le n)$.

It is guaranteed that the sum of $n$ and the sum of $q$ across all test cases does not exceed $2\cdot 10^5$.

Output

For each test case and for each guess, output the maximum distance to the farthest vertex that Chefir could reach from the starting point $v_i$ having $k_i$ stamina.

Example

Input

3
5
1 2
2 3
3 4
3 5
3
5 1
3 1
2 0
9
8 1
1 7
1 4
7 3
4 9
3 2
1 5
3 6
7
6 0
2 3
6 2
8 2
2 4
9 2
6 3
6
2 1
2 5
2 4
5 6
4 3
3
3 1
1 3
6 5

Output

2 1 2 
0 5 2 4 5 5 5 
1 3 4 

Note

In the first example:

  • In the first query, you can go from vertex $5$ to vertex $3$ (after which your stamina will decrease by $1$ and become $0$), and then you can go to vertex $4$;
  • In the second query, from vertex $3$ with $1$ stamina, you can only reach vertices $2$, $3$, $4$, and $5$;
  • In the third query, from vertex $2$ with $0$ stamina, you can only reach vertices $2$, $3$, $4$, and $5$;

解題思路

  賽時沒留意到 $k$ 是任意取值從而 $v$ 可能往上跳出根節點,導致沒處理越界情況 WA 麻了。發現後對 $k$ 與 $v$ 到根節點距離取最小值就過了,還以為寫了個假做法。

  定義 $d_v$ 表示節點 $v$ 的深度(規定根節點 $d_1 = 1$)。由於往父節方向點走會消耗 $1$ 點體力,因此 $v$ 最多往上走到距離其 $\min\{k, d_v - 1\}$ 的祖先,記為 $P$。由於往下走不消耗體力,因此從 $v$ 出發能走到子樹 $P$(以 $P$ 為根的子樹)中的任意一點,同時這也是從 $v$ 出發消耗體力不超過 $k$ 所能到達的所有點。所以距離 $v$ 最遠的點只能在子樹 $P$ 中找。

  我們知道樹中任意兩點 $u,v$ 構成路徑的長度可以表示成 $d_u + d_v - 2 \cdot \mathrm{lca}(u, v)$。設 $u$ 是子樹 $P$ 中的節點,將 $u$ 與 $v$ 構成的路徑按最近公共祖先進行分類,那麼這些最近公共祖先均是距離 $v$ 不超過 $\min\{k, d_v - 1\}$ 的祖先。假設 $p'$ 是 $v$ 的祖先,$p$ 是 從 $p'$ 再往上走一步的祖先,顯然 $p'$ 是 $p$ 的子節點。$u$ 和 $v$ 的最近公共祖先是 $p$ 當且僅當 $u$ 是子樹 $p$ 中的節點且不在子樹 $p'$ 中,如下圖所示。

G. Sakurako and Chefir

  定義 $f_1(u)$ 表示子樹 $u$ 中到 $u$ 的最大距離,$f_2(u)$ 表示子樹 $u$ 中到 $u$ 的次大距離。依次列舉 $v$ 的祖先 $p$,那麼在子樹 $p$ 且與 $v$ 構成的最近公共祖先是 $p$ 的節點中,到 $v$ 的最大距離就是 $\displaylines{\begin{cases}f_2(p) + d_v - d_p, &f(p') + 1 = f(p) \\ f_1(p) + d_v - d_p, &f(p') + 1 \ne f(p) \end{cases}}$。可以考慮倍增最佳化這個列舉過程。

  定義 $\mathrm{fa}(u,i)$ 表示從 $u$ 往上走 $2^i$ 步到達的節點。$g(u,i)$ 表示距離 $u$ 不超過 $2^i$ 的每個祖先 $p$ 中(不含 $u$)關於 $f_1(p) - d_p$ 或 $f_2(p) - d_p$ 的最大值(即對於每個 $p$ 只考慮在子樹 $p$ 且與 $u$ 構成的最近公共祖先是 $p$ 的節點)。狀態轉移方程就是

\begin{cases}
g(u,i) = \displaylines{\begin{cases}f_2(p_u) - d_{p_u}, &f(u) + 1 = f(p_u) \\ f_1(p_u) - d_{p_u}, &f(u) + 1 \ne f(p_u) \end{cases}} \, , &i=0 \\\\
g(u,i) = \max\{ g(u,i-1), \, g\left(\mathrm{fa}(u,i-1), i-1\right) \} \, , &i > 0
\end{cases}

  其中 $p_u = fa(u,0)$ 是 $u$ 的父節點。$g(u,i) + d_v$ 就是距離 $u$ 不超過 $2^i$ 的祖先所構成的子樹中,距離 $v$ 的最大距離。

  最後對於每個詢問 $v$ 和 $k$,先處理越界問題,即 $k \gets \min\{ k, d_v - 1 \}$。記 $t = d_v$,然後列舉 $k$ 的二進位制的每一位,如果第 $i$ 位是 $1$ 就往上跳 $2^i$ 步,同時將答案與 $g(v,i) + t$ 取最大值,並置 $v \gets fa(v, i)$。

  AC 程式碼如下,時間複雜度為 $O((n + q) \log{n})$:

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;

const int N = 2e5 + 5, M = N * 2;

int h[N], e[M], ne[M], idx;
int d[N], f1[N], f2[N];
int fa[N][18], g[N][18];

void add(int u, int v) {
    e[idx] = v, ne[idx] = h[u], h[u] = idx++;
}

void dfs1(int u, int p) {
    d[u] = d[p] + 1;
    f1[u] = f2[u] = 0;
    for (int i = h[u]; i != -1; i = ne[i]) {
        int v = e[i];
        if (v == p) continue;
        dfs1(v, u);
        int t = f1[v] + 1;
        if (t > f1[u]) f2[u] = f1[u], f1[u] = t;
        else if (t > f2[u]) f2[u] = t;
    }
}

void dfs2(int u, int p) {
    fa[u][0] = p;
    if (f1[p] == f1[u] + 1) g[u][0] = f2[p] - d[p];
    else g[u][0] = f1[p] - d[p];
    for (int i = 1; i <= 17; i++) {
        fa[u][i] = fa[fa[u][i - 1]][i - 1];
        g[u][i] = max(g[u][i - 1], g[fa[u][i - 1]][i - 1]);
    }
    for (int i = h[u]; i != -1; i = ne[i]) {
        int v = e[i];
        if (v == p) continue;
        dfs2(v, u);
    }
}

void solve() {
    int n, m;
    cin >> n;
    idx = 0;
    memset(h, -1, n + 1 << 2);
    for (int i = 0; i < n - 1; i++) {
        int u, v;
        cin >> u >> v;
        add(u, v), add(v, u);
    }
    dfs1(1, 0);
    dfs2(1, 0);
    cin >> m;
    while (m--) {
        int x, k;
        cin >> x >> k;
        k = min(k, d[x] - 1);
        int ret = f1[x], t = d[x];
        for (int i = 0; i <= 17; i++) {
            if (k >> i & 1 && x) {
                ret = max(ret, g[x][i] + t);
                x = fa[x][i];
            }
        }
        cout << ret << ' ';
    }
    cout << '\n';
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int t;
    cin >> t;
    while (t--) {
        solve();
    }
    
    return 0;
}

參考資料

  Codeforces Round 981 (Div. 3) - Codeforces:https://codeforces.com/blog/entry/135421