长链剖分 解 k级祖先问题
概念
长链剖分, 和重链剖分一样是一种链剖分, 只不过重儿子变成了长儿子。
称一个点的子树深度(这个概念是我yy的,在其他地方不一定适用)为:以这个点为根的子树中所有节点深度的最大值。
一个点的长儿子就是这个点的儿子中子树深度最大的那个儿子。
常见性质
1.对树长链剖分后, 所有链的 \(size\) ( \(length\) ) 之和为树的节点个数。
显然成立
2.一个点的 \(k\) 级祖先所在链的长度 \(\geq k\)
若这个点的 \(k\) 祖先与其在同一链中, 则性质成立。
若反之,则可以推出这个点的 \(k\) 祖先的儿子们的最大子树深度大于 \(k\), 性质成立。
算法流程
前置定义
定义 \(highbit(n)\) 为 \(\log_2(n)\) 的整数部分。
假设要求节点 \(x\) 的 \(k\) 级祖先。
记 \(r = 2^{highbit(k)}\)。
真 · 流程
求出 \(x\) 的 \(r\) 级祖先 \(y\), 问题转化为求 \(y\) 的 \(k-r\) 级祖先。(由于 \(r\) 为 \(2\) 的整次幂, 所以可以倍增处理后 \(O(1)\) 回答)
由二进制的性质, 可知 \(k-r<r\) 。
由 常见性质2, \(y\) 所在链的长度 \(\geq r\)。
故预处理出每个链 \(L\) 链顶的 \(1 \leq k \leq length(L)\) 级祖先和\(1 \leq k \leq length(L)\) 级儿子, 可以保证 \(y\) 的 \(k-r\) 级祖先必被包含其中。
时间复杂度分析
倍增预处理 \(O(n\log n)\)。
预处理每个链 \(L\) 的 \(length(L)\) 个祖先和儿子, 复杂度是 \(O(\sum_{L} length(L)) = O(n)\)。
显而易见, 经过预处理之后, 对某个 \(k\) 级祖先问题的回答是可以做到 \(O(1)\) 的。
板子题
AC代码
// 注意, 以一个点 x 为顶端的链的长度为 treedep[x]-dep[x]+1;
// 由于这个 sb 错误我调了很久qwq
// 希望看这篇博文的人引以为戒 qwq
#include<bits/stdc++.h>
using namespace std;
const int maxn = 5e5+15;
#define ui unsigned int
ui s;
inline ui get(ui x) {
x ^= x << 13;
x ^= x >> 17;
x ^= x << 5;
return s = x;
}
int n,q,rt;
vector<int>e[maxn],ks[maxn],kf[maxn];
int treedep[maxn],dep[maxn],son[maxn],top[maxn];
int f[21][maxn];
void po1(int x,int fa,int Dep) {
treedep[x]=dep[x]=Dep;
f[0][x]=fa;
for(int i=0;i<(int)e[x].size();++i) {
int y=e[x][i]; if(y==fa) continue;
po1(y,x,Dep+1);
if(treedep[y]>treedep[son[x]]) treedep[x]=treedep[son[x]=y];
}
}
void po2(int x,int tp) {
top[x]=tp;
if(son[x]) po2(son[x],tp);
for(int i=0;i<(int)e[x].size();++i) {
int y=e[x][i]; if(y==f[0][x]||y==son[x]) continue;
po2(y,y);
}
}
int highbit[maxn];
int kfa(int x,int k) {
if(!k) return x;
int r=highbit[k];
x=f[r][x];
k-=(1<<r);
if(dep[x]-k<dep[top[x]])
return kf[top[x]][dep[top[x]]-(dep[x]-k)];
else
return ks[top[x]][(dep[x]-k)-dep[top[x]]];
}
int ans[5000005];
int main()
{
cin>>n>>q>>s;
for(int i=1;i<=n;++i) {
int ff;scanf("%d",&ff);
if(ff) e[ff].push_back(i);
else rt=i;
}
po1(rt,0,1);
po2(rt,rt);
for(int k=1;k<=20;++k)
for(int i=1;i<=n;++i)
f[k][i] = f[k-1][f[k-1][i]];
for(int x=1;x<=n;++x) if(x==top[x]) {
int ns=x, nf=x;
for(int i=0;i<=treedep[x]-dep[x]+1;++i) {
ks[x].push_back(ns), kf[x].push_back(nf);
ns=son[ns], nf=f[0][nf];
}
}
for(int i=1;i<=n;++i) highbit[i] = log2(i);
for(int i=1;i<=q;++i) {
int x=((get(s) xor ans[i-1]) % n)+1;
int k=(get(s) xor ans[i-1])%dep[x];
ans[i] = kfa(x,k);
}
long long ANS = 0ll;
for(int i=1;i<=q;++i) ANS ^= 1ll*i*ans[i];
cout << ANS;
return 0;
}