题目传送门https://vjudge.net/problem/CSES-1687#author=GPT_zh
解题思路
其实和倍增法求 LCA 是一样的……
首先设 表示 号点的上面的第 个祖先是谁。
同倍增法:
然后,题目要求我们向上跳 个点。
枚举 (从大到小,想想为什么),然后每次跳时 。
若最后 ,那么就跳不完,说明没有,输出 -1.
否则输出答案即可。
代码
这里加了一个常数优化, 表示 的值。
#include<bits/stdc++.h>
using namespace std;
int n,q;
vector<int> g[200001];
int f[200001][31];
int lg[200001];
int dep[200001];
void dfs(int x,int fa)
{
dep[x]=dep[fa]+1;
f[x][0]=fa;
for(int i=1;i<=lg[dep[x]];i++)
{
f[x][i]=f[f[x][i-1]][i-1];
}
for(auto y:g[x])
{
if(y!=fa)
{
dfs(y,x);
}
}
}
int solve(int u,int k)
{
if(k==0)return u;
bool bj=0;
for(int i=lg[k];i>=0;i--)
{
if(f[u][i]!=-1&&k-(1<<i)>=0)
{
u=f[u][i];
k-=(1<<i);
bj=1;
}
}
if(k==0)return u;
return -1;
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n>>q;
int x;
for(int i=2;i<=n;i++)
{
cin>>x;
g[i].push_back(x);
g[x].push_back(i);
}
memset(f,-1,sizeof f);
lg[0]=1;
for(int i=1;i<=n;i++)
{
lg[i]=lg[i-1]+(1<<lg[i-1]==i);
}
dfs(1,-1);
int y;
while(q--)
{
cin>>x>>y;
cout<<solve(x,y)<<"\n";
}
}