一种用来合并子树中关于深度的信息的trick
重儿子定义为沿着重儿子走到的叶子深度最深。
1. 求 $k$ 级祖先
一个节点的 $k$ 级祖先所在的重链长度不小于 $k$。
证明显然。
1. 记录重链长度 $len[u]$ 以及链头 $top[u]$。
2. 记录倍增数组 $fa[u][sz]$。
3. 记录每条重链的链头往上跳重链长度的祖先 $up[u][len]$ 以及往下走重链长度的儿子 $down[u][len]$。
4. 记录每一个数字最高位的 $1$ $highbit[n]$。
预处理部分 $O(nlogn)$
先要求 $u$ 的 $k$ 级祖先。$u$ 所在的重链长度不一定大于 $k$,所以无法通过 3 得到的数组 $O(1)$ 得到答案。
可以先用倍增数组往上跳 $2^{highbit[k]}$ 步,得到节点 $v$。
$v$ 为 $u$ 的 $2^{highbit[k]}$级祖先,那么这条重链长度不小于 $2^{highbit[k]}$。
就可以用 3 得到的数组 $O(1)$ 得到答案了。

#include <bits/stdc++.h>
const int N = 3e5 + 7;
int fa[N][20], n, son[N], len[N], sz[N], dep[N], highbit[N];
int top[N];
std::vector<int> vec[N];
void dfs1(int u, int pre) {
sz[u] = dep[u] = dep[pre] + 1;
fa[u][0] = pre;
for (int i = 1; i < 20; i++)
if (fa[u][i - 1])
fa[u][i] = fa[fa[u][i - 1]][i - 1];
else
break;
for (int v: vec[u]) {
if (v == pre) continue;
dfs1(v, u);
if (sz[v] > sz[son[u]]) son[u] = v, sz[u] = sz[v];
}
}
void dfs2(int u, int tp) {
top[u] = tp;
len[u] = sz[u] - dep[tp] + 1;
if (!son[u]) return;
dfs2(son[u], tp);
for (int v: vec[u])
if (v != fa[u][0] && v != son[u])
dfs2(v, v);
}
std::vector<int> up[N], down[N];
int query(int u, int k) {
if (k > dep[u]) return 0;
if (!k) return u;
u = fa[u][highbit[k]];
k ^= 1 << highbit[k];
if (!k) return u;
if (dep[u] - dep[top[u]] == k) return top[u];
if (dep[u] - dep[top[u]] > k) return down[top[u]][dep[u] - dep[top[u]] - k - 1];
return up[top[u]][k - dep[u] + dep[top[u]] - 1];
}
int main() {
scanf("%d", &n);
for (int i = 1; i < n; i++) {
int u, v;
scanf("%d%d", &u, &v);
vec[u].push_back(v);
vec[v].push_back(u);
}
dfs1(1, 0);
dfs2(1, 1);
for (int i = 1; i <= n; i++) if (i == top[i]) {
int l = 0, u = i;
while (l++ < len[i] && u) u = fa[u][0], up[i].push_back(u);
l = 0, u = i;
while (l++ < len[i]) u = son[u], down[i].push_back(u);
}
for (int i = 1, bit = 1; i <= n; i++) {
if ((i >> bit) & 1) bit++;
highbit[i] = bit - 1;
}
int q;
scanf("%d", &q);
for (int ans = 0; q--; ) {
int u, k;
scanf("%d%d", &u, &k);
u ^= ans, k ^= ans;
printf("%d\n", ans = query(u, k));
}
return 0;
}
