很早之前写过两篇线性时间的 LCA & RMQ 的做法。现在把四毛子的另外一个例子补完。
The Problem
所谓 Level Ancestor 问题
这个点的 级祖先是谁?
我们的任务是,给定一颗有根树,回答若干次这样的询问。要求复杂度
在下文中,记一个节点的深度
The Solution
Trick 1, Path Decomposition
第一个技巧是链剖分。首先大家都熟知重链剖分,在重链剖分之后每个节点到根的路径上的轻边只有
因此我们只要不断向上跳,直到寻找一个包含第
Trick 2, Binary Lifting
下一个熟知的技巧是倍增。对于每个节点
Trick 3, Ladders
我们将上述两个技巧结合起来。首先,我们假设要求
Trick 4, Mo4R
首先我们可以发现,我们的只需要记录所有叶子节点的
设
所有宏节点会形成一颗树,称之为宏树。宏树的每个叶子在原树中大小
考虑微节点形成的微连通块,每个这样的块都是原树的子树,且大小不超过
因此,上述算法的总预处理复杂度是:
代码
代码如下:
#include "bits/stdc++.h"
using namespace std;
namespace
{
using ui = unsigned int;
namespace PRNG
{
;
ui s
ui get() {
^= s << 13;
s ^= s >> 17;
s ^= s << 5;
s return s;
}
}
struct HighBit
{
[1024];
ui table
() {
HighBit[0] = 0;
table[1] = 0;
tablefor (ui i = 2; i < 1024; ++i) {
[i] = table[i >> 1] + 1;
table}
}
ui operator()(ui x) {
if (x >> 20) return table[x >> 20] + 20;
if (x >> 10) return table[x >> 10] + 10;
return table[x];
}
operator[](ui x) {
ui return 1 << operator()(x);
}
} highbit;
ui concat(ui x, ui y) {
if (y == 0) return x;
return (x << (1 + highbit(y))) | y;
}
const int max_n = 555555;
int n, q;
int threshold;
int parent[max_n];
int dfn[max_n], dfa[max_n], dfr[max_n];
int tme;
int dep[max_n];
int height[max_n];
int preferred[max_n];
int ladder_root[max_n];
int *ladder_table[max_n];
int siz[max_n];
int *jump_table[max_n];
bool is_jump_node[max_n];
int any_jump_down[max_n];
int micro_root[max_n];
int micro_root_dis[max_n];
[max_n];
ui shapeint dfs_stack[max_n];
const int bit_size = 1 << 14;
int **micro_table[bit_size];
struct Graph
{
int beg[max_n], nxt[max_n], to[max_n];
int e;
void add_edge(int x, int y) {
++e;
[e] = y;
to[e] = beg[x];
nxt[x] = e;
beg}
} g;
void dfs(int x) {
[dfn[x] = ++tme] = x;
dfa[x] = dep[parent[x]] + 1;
dep[x] = 1;
siz[x] = 0;
heightfor (int i = g.beg[x]; i; i = g.nxt[i]) {
int y = g.to[i];
(y);
dfs[x] += siz[y];
sizif (height[y] > height[x]) {
[x] = height[y];
height[x] = y;
preferred}
}
++height[x];
[x] = tme;
dfr}
int cnt1 = 0, cnt2 = 0;
int level_ancestor(int x, int k) {
// out from micro tree
if (micro_root[x] && k > micro_root_dis[x]) {
-= micro_root_dis[x] + 1;
k = parent[micro_root[x]];
x }
// on macro tree
if (any_jump_down[x]) {
+= dep[any_jump_down[x]] - dep[x];
k = any_jump_down[x];
x }
if (is_jump_node[x]) {
if (k == 0) return x;
= jump_table[x][highbit(k)];
x ^= highbit[k];
k int z = ladder_root[x];
return ladder_table[z][dep[x] - k - dep[z]];
}
// on micro tree
int z = micro_root[x];
int **table = micro_table[shape[z]];
return dfa[dfn[z] + table[dfn[x] - dfn[z]][k]];
}
}
int main() {
cin.sync_with_stdio(false);
cin.tie(nullptr);
cin >> n >> q >> PRNG::s;
int root = 0;
for (int i = 1; i <= n; ++i) {
cin >> parent[i];
.add_edge(parent[i], i);
gif (parent[i] == 0) {
= i;
root }
}
= log(n) / log(2) / 4 + 1;
threshold (root);
dfs// calculate jump node
memset(is_jump_node, 1, sizeof is_jump_node);
for (int i = n; i >= 1; --i) {
int x = dfa[i];
if (siz[x] <= threshold) {
[x] = false;
is_jump_node} else {
[parent[x]] = false;
is_jump_node}
if (is_jump_node[x]) {
[x] = x;
any_jump_down}
if (any_jump_down[x]) {
[parent[x]] = any_jump_down[x];
any_jump_down}
}
// calculate jump table
for (int i = 1; i <= n; ++i) {
int x = dfa[i];
[dep[x]] = x;
dfs_stackif (is_jump_node[x]) {
int len = highbit(dep[x] - 1) + 1;
[x] = new int[len];
jump_tablefor (int j = 0; j < len; ++j) {
[x][j] = dfs_stack[dep[x] - (1 << j)];
jump_table}
}
}
// calculate the ladder info
for (int i = 1; i <= n; ++i) {
int x = dfa[i];
[dep[x]] = x;
dfs_stackint &z = ladder_root[x];
if (x != preferred[parent[x]]) {
= x;
z
[x] = new int[height[x] * 2] + height[x];
ladder_table[x][0] = x;
ladder_tablefor (int i = 1; i <= height[x] && i <= dep[x]; ++i) {
[x][-i] = dfs_stack[dep[x] - i];
ladder_table}
} else {
= ladder_root[parent[x]];
z
[z][dep[x] - dep[z]] = x;
ladder_table}
}
// calculate micro tree info
for (int i = n; i >= 1; --i) {
int x = dfa[i];
if (siz[x] <= threshold) {
[x] <<= 1;
shape[x] += highbit[shape[x]] << 1;
shapeif (siz[parent[x]] <= threshold) {
[parent[x]] = concat(shape[x], shape[parent[x]]);
shape}
}
}
for (int i = 1; i <= n; ++i) {
int x = dfa[i];
if (micro_root[parent[x]]) {
[x] = micro_root[parent[x]];
micro_root[x] = micro_root_dis[parent[x]] + 1;
micro_root_dis} else if (siz[x] <= threshold) {
[x] = x;
micro_root[x] = 0;
micro_root_dis}
}
for (int i = 1; i <= n; ++i) {
int x = dfa[i];
if (micro_root[x] == x) {
if (micro_table[shape[x]] != nullptr) {
continue;
}
int **&table = micro_table[shape[x]];
= new int*[siz[x]];
table for (int j = dfn[x]; j <= dfr[x]; ++j) {
int y = dfa[j];
int len = dep[y] - dep[x];
[j - dfn[x]] = new int[len + 1];
table[j - dfn[x]][0] = j - dfn[x];
tableif (y != x) {
int z = parent[y];
memcpy(table[j - dfn[x]] + 1, table[dfn[z] - dfn[x]],
* sizeof(int));
len }
}
}
}
// answer the queries
unsigned long long ans = 0;
int lastans = 0;
for (int i = 1; i <= q; ++i) {
int x = (PRNG::get() xor lastans) % n + 1;
int k = (PRNG::get() xor lastans) % dep[x];
int y = level_ancestor(x, k);
= y;
lastans ^= i * static_cast<unsigned long long>(y);
ans }
cout << ans << endl;
// cleaning up
for (int x = 1; x <= n; ++x) {
if (jump_table[x] != nullptr)
delete[] jump_table[x];
if (ladder_table[x] != nullptr)
delete[] (ladder_table[x] - height[x]);
}
for (int x = 1; x < (bit_size); ++x) {
if (micro_table[x]) {
int len = highbit(x) / 2;
for (int i = 0; i < len; ++i) {
delete[] micro_table[x][i];
}
delete[] micro_table[x];
}
}
return 0;
}