1. 程式人生 > 其它 >luogu P5903 【模板】樹上 k 級祖先

luogu P5903 【模板】樹上 k 級祖先

題面傳送門
考慮長鏈剖分。我們對於每個鏈頂存下這條鏈上的點和往上\(len\)長度個點。
然後倍增預處理出一個點往上\(2^i\)祖先。
對於一個點的\(k\)\(k\)級祖先,我們讓他先跳\(2^{\lfloor logk\rfloor}\)級祖先,此時這個點所在的長鏈一定大於等於\(2^{\lfloor logk\rfloor}\)
然後跳到鏈頂看看往上跳還是往下跳直接查就好了。時間複雜度\(O(nlogn+q)\)
code:

#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define re register
#define ll long long
#define db double
#define N 500000
#define K 150
#define mod 10007
#define eps (1e-9)
#define U unsigned int
#define it iterator
#define Gc() getchar() 
#define Me(x,y) memset(x,y,sizeof(x))
#define d(x,y) (n*(x-1)+(y))
using namespace std;
int n,m,k,x,y,z,d[N+5],fa[N+5][25],lg[N+5],root,top[N+5],len[N+5],son[N+5],st[N+5],sh,Ans;ll ToT;vector<int> Up[N+5],Down[N+5];U S;
struct yyy{int to,z;};I U get(U x) {x^=x<<13;x^=x>>17;x^=x<<5;return S=x;}
struct ljb{int head,h[N+5];yyy f[N+5];I void add(int x,int y){f[++head]=(yyy){y,h[x]};h[x]=head;}}s;
I void dfs1(int x,int last){
	d[x]=d[last]+1;yyy tmp;int i;for(i=1;fa[x][i-1];i++)fa[x][i]=fa[fa[x][i-1]][i-1];for(i=s.h[x];i;i=tmp.z) tmp=s.f[i],dfs1(tmp.to,x),len[son[x]]<len[tmp.to]&&(son[x]=tmp.to);len[x]=len[son[x]]+1;
}
I void dfs2(int x,int last){
	int i;yyy tmp;top[x]=last;st[++sh]=x;Down[top[x]].push_back(x);if(top[x]==x){for(i=1;i<=min(len[x],d[x]);i++) Up[x].push_back(st[sh-i+1]);}if(!son[x])return (void)(sh--);dfs2(son[x],last);for(i=s.h[x];i;i=tmp.z) tmp=s.f[i],tmp.to^son[x]&&(dfs2(tmp.to,tmp.to),0);sh--;
}
int main(){
	freopen("1.in","r",stdin);
	re int i;scanf("%d%d%u",&n,&m,&S);for(i=2;i<=n;i++) lg[i]=lg[i/2]+1;for(i=1;i<=n;i++) scanf("%d",&fa[i][0]),fa[i][0]?(s.add(fa[i][0],i),0):(root=i);dfs1(root,0);dfs2(root,root);
	for(i=1;i<=m;i++){x=(get(S)^Ans)%n+1,y=(get(S)^Ans)%d[x];if(!y){Ans=x;ToT^=1ll*i*Ans;continue;}z=top[fa[x][lg[y]]],Ans=(d[x]-d[z]>y?Down[z][d[x]-d[z]-y]:Up[z][y-d[x]+d[z]]),ToT^=1ll*Ans*i;}printf("%lld\n",ToT);
}