长链剖分
https://www.luogu.com.cn/problem/P5903
与重链剖分类似,存长儿子以及长度,从叶子跳到根是 \(\mathcal{O}(\sqrt{n})\) 的.
可以 \(\mathcal{O}(1)\) 查询 \(k\) 级祖先,只对长链头维护 \(up\) 和 \(down\),例如 \(up[dfn[u]+j]\) 表示 \(u\) 向上跳 \(j\) 步到达的节点,维护倍增表.
查询 \(k\) 级祖先步骤:获取 \(k\) 的最高有效位 \(B\),向上跳 \(2^B\) 步,然后跳到链头,此时剩下的步数(可能为负)用 \(up\) 和 \(down\) 调整.
因为长链的性质,剩下的步数一定不会越界.
//author:kzssCCC
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define ui unsigned int
ui s;
inline ui get(ui x) {
x ^= x << 13;
x ^= x >> 17;
x ^= x << 5;
return s = x;
}
void solve(){
int n,q;
cin >> n >> q >> s;
vector<vector<int>> adj(n+1);
vector<int> par(n+1,-1);
for (int i=1;i<=n;i++){
cin >> par[i];
if (par[i]==0){
par[i] = -1;
}
else{
adj[par[i]].push_back(i);
}
}
int rt = 1;
while (rt<=n && par[rt]!=-1){
rt++;
}
vector<int> depth(n+1),son(n+1),top(n+1),dfn(n+1),len(n+1),up(n+1),down(n+1);
vector<vector<int>> next(n+1,vector<int>(21,-1));
int timer = 1;
function<void(int)> dfs = [&](int u){
int pos = -1;
int mx = 0;
len[u] = 1;
for (auto& v:adj[u]){
if (v==par[u]) continue;
next[v][0] = u;
depth[v] = depth[u]+1;
dfs(v);
if (len[v]>mx){
mx = len[v];
pos = v;
}
}
son[u] = pos;
len[u] += mx;
};
dfs(rt);
function<void(int,int)> dfs2 = [&](int u,int head){
dfn[u] = timer++;
top[u] = head;
if (son[u]!=-1){
dfs2(son[u],head);
}
for (auto& v:adj[u]){
if (v==par[u] || v==son[u]) continue;
dfs2(v,v);
}
};
dfs2(rt,rt);
for (int k=1;k<=20;k++){
for (int i=1;i<=n;i++){
if (next[i][k-1]==-1) continue;
next[i][k] = next[next[i][k-1]][k-1];
}
}
for (int i=1;i<=n;i++){
if (top[i]!=i) continue;
int x=i,y=i;
for (int j=0;j<len[i];j++){
up[dfn[i]+j] = x;
down[dfn[i]+j] = y;
if (x!=-1) x = par[x];
if (y!=-1) y = son[y];
}
}
vector<int> res(q+1);
for (int i=1;i<=q;i++){
int x = (get(s)^res[i-1])%n+1;
int k = (get(s)^res[i-1])%(depth[x]+1);
if (k==0){
res[i] = x;
continue;
}
int B = 31-__builtin_clz(k);
x = next[x][B];
k -= 1<<B;
k -= depth[x]-depth[top[x]];
x = top[x];
if (k>=0){
x = up[dfn[x]+k];
}
else{
x = down[dfn[x]-k];
}
res[i] = x;
}
ll xr = 0;
for (int i=1;i<=q;i++){
xr^=(ll)i*res[i];
}
cout << xr << '\n';
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int t = 1;
// cin >> t;
while (t--) solve();
return 0;
}

浙公网安备 33010602011771号