洛谷P5903 【模板】树上 K 级祖先 题解 长链剖分经典应用题
题目链接:https://www.luogu.com.cn/problem/P5903
解题思路来自 xht大佬的博客
示例程序:
#include <bits/stdc++.h>
using namespace std;
#define ui unsigned int
ui s;
inline ui get(ui x) {
x ^= x << 13;
x ^= x >> 17;
x ^= x << 5;
return s = x;
}
const int maxn = 5e5 + 5, maxq = 5e6 + 5;
int n, q, rt, fa[maxn][20], tp[maxn], son[maxn];
vector<int> g[maxn], up[maxn], down[maxn];
ui ans[maxq], d[maxn], dep[maxn];
void dfs1(int u) {
dep[u] = d[u] = d[ fa[u][0] ] + 1;
for (int i = 0; fa[u][i]; i++)
fa[u][i+1] = fa[ fa[u][i] ][i];
for (auto v : g[u]) {
fa[v][0] = u;
dfs1(v);
if (dep[v] > dep[son[u]]) {
son[u] = v;
dep[u] = dep[v];
}
}
}
void dfs2(int u, int top) {
tp[u] = top;
if (u == top) {
for (int i = 0, x = u, y = u; i <= dep[u] - d[u]; i++, x = fa[x][0], y = son[y]) {
up[u].push_back(x);
down[u].push_back(y);
}
}
if (son[u]) dfs2(son[u], top);
for (auto v : g[u])
if (v != son[u])
dfs2(v, v);
}
ui cal(int x, int k) {
if (!k)
return x;
int kk = log2(k);
x = fa[x][kk];
k -= 1 << kk;
k -= d[x] - d[ tp[x] ];
x = tp[x];
return (k >= 0) ? up[x][k] : down[x][-k];
}
int main() {
scanf("%d%d%u", &n, &q, &s);
for (int i = 1, p; i <= n; i++) {
scanf("%d", &p);
if (!p) rt = i;
else {
g[p].push_back(i);
fa[i][0] = p;
}
}
dfs1(rt);
dfs2(rt, rt);
for (int i = 1; i <= q; i++) {
ui x = (get(s) ^ ans[i-1]) % n + 1;
ui k = (get(s) ^ ans[i-1]) % d[x];
ans[i] = cal(x, k);
}
long long res = 0;
for (int i = 1; i <= q; i++)
res ^= 1ll * i * ans[i];
printf("%lld\n", res);
return 0;
}