vijos lxhgww的奇思妙想
vijos lxhgww的奇思妙想
本题我们可以通过倍增的预处理\(O(nlogn)\),然后对本题进行长链剖分。 对于要求k级祖先,我们先用预处理好的倍增数组走到x的\(highbit(k)\)祖先上面去(10的highbit就是8,剩余的k就是2了),x变成这个highbit的祖先。然后我们讨论x和\(top[x]\)之间的距离,如果大于等于剩余的k,那么我们就求\(top[x]\)下面距离为\(dep[x]-dep[top[x]]-k\)的长链的节点编号。如果小于等于剩下的k,我们就求\(top[x]\)上面的距离为\(k-dep[x]+dep[top[x]]\)的节点的编号。这些上面的节点和下面的节点我们都可以提前预处理,因为我们只要记录每个长链的顶端节点的上下节点就可以,时间复杂度是\(o(n)\)的。
本题时间复杂度最高的地方在于倍增求\(2^k\)的祖先,每次在线处理k级祖先是\(o(1)\)的。 总的时间复杂度也是\(O(nlogn\))。
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
int const N=500000+10;
struct edge{
int to,nt;
}e[N<<1];
int f[N][20],n,cnt,h[N],top[N],son[N],dep[N],md[N],len[N],m,hb[N<<1];
vector<int> U[N],D[N];
void add(int a,int b){
e[++cnt].to=b;
e[cnt].nt=h[a];
h[a]=cnt++;
}
void dfs(int x,int fa){
dep[x]=md[x]=dep[fa]+1; f[x][0]=fa;
for(int i=1;i<=18;i++) f[x][i]=f[f[x][i-1]][i-1];
for(int i=h[x];i;i=e[i].nt){
int v=e[i].to;
if(v==fa) continue;
dfs(v,x);
if(md[x]<md[v])
son[x]=v,md[x]=md[v];
}
}
void dfs2(int x,int fa,int tp){
top[x]=tp; len[x]=md[x]-dep[top[x]]+1;
for(int i=h[x];i;i=e[i].nt){
int v=e[i].to;
if(v==fa) continue;
if(v==son[x]) dfs2(v,x,tp);
else dfs2(v,x,v);
}
}
int query(int x,int k){
if(dep[x]-1<k) return 0;
if(k==0) return x;
x=f[x][hb[k]];
k^=1<<hb[k];
if(dep[x]-dep[top[x]]>=k)
return D[top[x]][dep[x]-dep[top[x]]-k];
else
return U[top[x]][k-dep[x]+dep[top[x]]];
}
int main(){
scanf("%d",&n);
for(int i=1;i<n;i++){
int x,y;
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
dfs(1,0);
dfs2(1,1,1);
for(int i=1;i<=n;i++)
if(top[i]==i){
int x=i,k=0;
while (x && k<len[i])
U[i].push_back(x),k++,x=f[x][0];
x=i,k=0;
while (x && k<len[i])
D[i].push_back(x),k++,x=son[x];
}
for(int i=1;i<=19;i++)
for(int j=(1<<i-1);j<(1<<i);j++)
hb[j]=i-1;
int ans=0;
scanf("%d",&m);
while (m--){
int x,y;
scanf("%d%d",&x,&y);
x^=ans; y^=ans;
printf("%d\n",ans=query(x,y));
}
return 0;
}