洛谷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;
}
posted @ 2025-07-15 16:17  quanjun  阅读(6)  评论(0)    收藏  举报