树上 k 级祖先

P5903 【模板】树上 K 级祖先

显然我们可以通过类似于求 lca 的方法求这个 k 级祖先,单次复杂度 \(O(\log n)\)

我们考虑长剖。然后对于每一条长链,设其长度为 \(len\),记录其向上和向下的 \(len\) 个点。然后类似于 lca 预处理 \(2^k\) 处的祖先。
查询的时候就是找到其二进制下最大的祖先,然后找到这个祖先的链顶,然后看深度是多了还是少了,然后直接查询预处理的东西即可。
正确性证明的话就是任意一个点的 k 级祖先所在的长链的长度至少为 k。显然,于是正确性也成立。

code

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ui unsigned int
ui s;
inline ui get(ui x) {
	x ^= x << 13;
	x ^= x >> 17;
	x ^= x << 5;
	return s = x; 
}
#define int long long 
const int N=1e6+7;
const int M=20;
int n,m,f[N][M],rt,tot[N],updep[N],top[N],dep[N],son[N],len[N],pw[N],ci[N];
vector <int> q[N],up[N],down[N];
void dfs1(int u){
	dep[u]=updep[u]=dep[f[u][0]]+1;
	for(int i=1;i<=18;i++) f[u][i]=f[f[u][i-1]][i-1];
	for(int i=0;i<tot[u];i++){int v=q[u][i];dfs1(v);if(updep[u]<updep[v]) updep[u]=updep[v],son[u]=v;}
}
void dfs2(int u,int t){
	top[u]=t;up[u].push_back(u),down[u].push_back(u);len[t]++;
	if(son[u]) dfs2(son[u],t);
	for(int i=0;i<tot[u];i++){int v=q[u][i];if(v==son[u]) continue;dfs2(v,v);}
	for(int i=1,v1=f[u][0],v2=son[u];i<=len[u];i++) up[u].push_back(v1),v1=f[v1][0],down[u].push_back(v2),v2=son[v2];
}
int query(int x,int k){
	if(k==0) return x;
	x=f[x][ci[k]],k-=pw[k];int tmp=x;
	if(k==0) return x;
	x=top[x];k-=dep[tmp]-dep[x];
	if(k>=0) return up[x][k];
	else return down[x][-k];
}
signed main()
{
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	cin>>n>>m>>s;
	for(int i=1,tmp=0;i<=2*n;i++) {if(i==1<<(tmp+1))tmp++;pw[i]=1<<tmp,ci[i]=tmp;}
	for(int i=1;i<=n;i++) cin>>f[i][0],rt=f[i][0]==0?i:rt,q[f[i][0]].push_back(i),tot[f[i][0]]++;
	dfs1(rt);dfs2(rt,rt);int lst=0,tmp=0;
	for(int i=1,x,k;i<=m;i++){
		x=(get(s)^lst)%n+1;k=(get(s)^lst)%dep[x];
		lst=query(x,k);tmp^=(i*lst);
	}
	cout<<tmp<<'\n';return 0;
}
posted @ 2025-07-22 09:47  all_for_god  阅读(37)  评论(0)    收藏  举报