例题:
P5903 【模板】树上 k 级祖先
题目描述
思路
长链剖分模板题。
长链剖分:
- 计算 \(f[i][j]\) 表示 \(i\) 的 \(2^j\) 级祖先;
- 计算 \(up[i][j]\) 表示 \(i\) 的 \(j\) 级祖先;
- 计算 \(down[i][j]\) 表示在长链上从 \(i\) 向下走 \(j\) 步到达的祖先。
- 计算 \(i\) 的 \(k\) 级祖先,先让 \(i\) 跳到 \(2^\left\lfloor \log_2k \right\rfloor\) 级祖先,\(k\) 减去 \(2^\left\lfloor \log_2k \right\rfloor\),再让 \(i\) 跳到长链顶端,\(k\) 减去 \(dep[i] - dep[top[i]]\),最后如果 \(k \ge 0\),那么答案就是 \(up[i][k]\),否则 \(k < 0\),答案就是 \(down[i][-k]\)。
代码
// Problem: P5903
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P5903
// Memory Limit: 500 MB
// Time Limit: 3000 ms
#include <bits/stdc++.h>
using namespace std;
using uint = unsigned int;
#define int long long
const int N = 500010, M = 20;
struct edge {
int to, next;
} e[N];
int head[N], idx;
void add(int u, int v) {
idx++;
e[idx].to = v;
e[idx].next = head[u];
head[u] = idx;
}
int n, q, s;
uint get_rand(uint x) {
x ^= x << 13;
x ^= x >> 17;
x ^= x << 5;
return s = x;
}
int rt;
int fa[N][M];
void initfa() {
for (int j = 1; j < M; j++) {
for (int i = 1; i <= n; i++) {
fa[i][j] = fa[fa[i][j - 1]][j - 1];
}
}
}
int dep[N], ds[N], son[N];
void dfs(int u) {
dep[u] = ds[u] = dep[fa[u][0]] + 1;
for (int i = head[u]; i; i = e[i].next) {
int to = e[i].to;
dfs(to);
if (ds[to] > ds[u]) {
ds[u] = ds[to];
son[u] = to;
}
}
}
vector<int> up[N];
vector<int> down[N];
int belong[N];
void init(int u, int p) {
belong[u] = p;
if (u == p) {
int tmp = u;
for (int i = 0; i <= ds[u] - dep[u]; i++) {
up[u].push_back(tmp);
tmp = fa[tmp][0];
}
tmp = u;
for (int i = 0; i <= ds[u] - dep[u]; i++) {
down[u].push_back(tmp);
tmp = son[tmp];
}
}
if (son[u]) init(son[u], p);
for (int i = head[u]; i; i = e[i].next) {
int to = e[i].to;
if (to == son[u]) continue;
init(to, to);
}
}
int query(int u, int k) {
if (!k) return u;
u = fa[u][__lg(k)];
k -= 1 << (__lg(k));
k -= dep[u] - dep[belong[u]];
u = belong[u];
if (k >= 0) return up[u][k];
else return down[u][-k];
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n >> q >> s;
for (int i = 1; i <= n; i++) {
cin >> fa[i][0];
if (!fa[i][0]) rt = i;
if (fa[i][0]) add(fa[i][0], i);
}
initfa();
dfs(rt);
init(rt, rt);
int ans = 0, res = 0;
int x, k;
for (int i = 1; i <= q; i++) {
x = ((get_rand(s) ^ ans) % n) + 1;
k = ((get_rand(s) ^ ans) % dep[x]);
ans = query(x, k);
res ^= (i * ans);
}
cout << res << '\n';
return 0;
}
标签:长链,剖分,idx,int,up,down
From: https://www.cnblogs.com/Yuan-Jiawei/p/17657737.html