Loading

长链剖分

例题:

P5903 【模板】树上 k 级祖先

题目描述

image

思路

长链剖分模板题。

长链剖分:

  1. 计算 \(f[i][j]\) 表示 \(i\)\(2^j\) 级祖先;
  2. 计算 \(up[i][j]\) 表示 \(i\)\(j\) 级祖先;
  3. 计算 \(down[i][j]\) 表示在长链上从 \(i\) 向下走 \(j\) 步到达的祖先。
  4. 计算 \(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;
}
posted @ 2023-08-25 18:39  SunnyYuan  阅读(3)  评论(0编辑  收藏  举报