树上 K 级祖先
基于重链剖分可以在 \(O(\log n)\) 的复杂度内求出树上一个点的 \(K\) 级祖先。
\(u\) 的 \(K\) 级祖先:定义 \(u\) 的父节点为 \(u\) 的 \(1\) 级祖先,记作 \(fa(u,1)\);再递归定义 \(fa(u,i)=fa(fa(u,i-1),1)\),那么 \(fa(u,K)\) 被称为 \(u\) 的 \(K\) 级祖先。
具体而言,重链剖分完后,我们在重链上跳。如果当前当前节点与链顶的距离小于等于 \(K\),那就跳到更上一条重链,同时将 \(K\) 减去该距离;否则说明 \(K\) 级祖先在当前重链上,那么该重链上编号比当前节点小 \(K\) 的点即为所求。整个过程基于重链剖分后单条重链上的节点编号连续的性质。
模板题:P5903 【模板】树上 K 级祖先。
什么你说正解是长链剖分?不管了反正重链剖分似乎跑的更快呢。
#include<bits/stdc++.h>
using namespace std;
const int N = 5e5 + 10;
int n, q;
long long lastans, ans;
unsigned int s;
inline unsigned int get(unsigned int x)
{
x ^= x << 13;
x ^= x >> 17;
x ^= x << 5;
return s = x;
}
vector<int> e[N];
int root;
int dep[N], fa[N], siz[N], hs[N];
int top[N], id[N], ID[N], cnt;
void dfs1(int u, int father)
{
dep[u] = dep[father] + 1;
fa[u] = father;
siz[u] = 1;
int maxson = -1;
for(auto i : e[u])
{
if(i == father)
{
continue;
}
dfs1(i, u);
siz[u] += siz[i];
if(maxson < siz[i])
{
maxson = siz[i];
hs[u] = i;
}
}
}
void dfs2(int u, int topf)
{
top[u] = topf;
id[u] = ++ cnt;
ID[cnt] = u;
if(hs[u] == 0)
{
return;
}
dfs2(hs[u], topf);
for(auto i : e[u])
{
if(i == fa[u] || i == hs[u])
{
continue;
}
dfs2(i, i);
}
}
int faK(int x, int K)//K级祖先
{
while(K >= id[x] - id[top[x]] + 1 && x != root)
{
K -= (id[x] - id[top[x]] + 1);
x = fa[top[x]];
}
return ID[id[x] - K];
}
int main()
{
cin >> n >> q >> s;
for(int i = 1; i <= n; i ++)
{
scanf("%d", &fa[i]);
if(fa[i] == 0)
{
root = i;
continue;
}
e[i].push_back(fa[i]);
e[fa[i]].push_back(i);
}
dfs1(root, 0);
dfs2(root, root);
for(int i = 1; i <= q; i ++)
{
int x = (get(s) ^ lastans) % n + 1;
int K = (get(s) ^ lastans) % dep[x];
lastans = faK(x, K);
ans ^= (i * lastans);
}
cout << ans;
return 0;
}

浙公网安备 33010602011771号