题意:
给出一棵树,然后q个询问(u,k),每个询问代表以u为子树根,向下遍历(序号小的优先),问遍历到第k个元素是多少?如果k大于这棵子树的节点总数,那么输出-1.
思路:
首先n和q是20000的,如果每次询问都遍历一次,那么复杂度是n^2,肯定会超时。所以我们可以遍历整棵树,只遍历一次,在遍历的时候记下每个子树根的起点和终点,然后把遍历的值放在一个数组中,最后每次询问时,我们可以直接输出结果,这样时间复杂度为n。
代码:
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<vector>
#include<algorithm>
using namespace std;
int vis[200005];
int se[200005][2];//se[i][0]代表以i为子树根的起点 se[i][1]代表终点。
int ans[2000005];//保存整个树的遍历结果,也就是以1为根的深搜
vector<int>V[200005];
int kas;//代表ans数组记录到kas个了
void dfs(int k)
{
vis[k]=1;
se[k][0]=++kas;//记录起点
ans[kas]=k;
int len=V[k].size();
for(int i=0;i<len;i++)
{
if(!vis[V[k][i]])
{
dfs(V[k][i]);
}
}
se[k][1]=kas;//记录终点
return;
}
int main()
{
int n,q;
while(~scanf("%d%d",&n,&q))
{
kas=0;
for(int i=0;i<=n;i++)
{
V[i].clear();
se[i][0]=se[i][1]=0;
ans[i]=0;
vis[i]=0;
}
int root;
for(int i=2;i<=n;i++)
{
scanf("%d",&root);
V[root].push_back(i);
}
for(int i=1;i<=n;i++)
{
sort(V[i].begin(),V[i].end());
}
dfs(1);
int u,k;
while(q--)
{
scanf("%d%d",&u,&k);
if(k>se[u][1]-se[u][0]+1)
{
printf("-1\n");
}
else
printf("%d\n",ans[se[u][0]+k-1]);
}
}
}