长链剖分

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;
}
posted @ 2026-07-15 20:43  kzssCCC  阅读(6)  评论(0)    收藏  举报