算是很水很裸的一道 dfs树上搜索
原本是想记录 每个点的 子节点 所包含的 点集分支内 有多少个点
如果结果在这个范围内,就搜索这个树枝,这样就是一条线路 的查询 平均查询复杂度为 O(log(n))
然后完整复杂度为 n*logn ,估计数据出了那种一条直线的树,就T了,改用下面的方法就过了。
先根遍历的节点记录
每个点都有它的子节点
- 记录每个点(算上这个点) 的子图 内点个数
- 记录每个点从 1号点 开始搜索的次序 (eg:第四个搜索到的点 -> 对应 5)
- 记录一个点 在搜索时的 序号(eg: 6 是 第五个搜索到的点)
然后 判断完这个点所包含的点集是不是有k个点 ,如果有直接O(1)查询就完事了
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <iostream>
#include <cmath>
#include <map>
#include <queue>
#include <algorithm>
#include <set>
#include <vector>
#include <stack>
#define Clear( x , y ) memset( x , y , sizeof(x) );
#define Qcin() std::ios::sync_with_stdio(false);
using namespace std;
typedef long long LL;
const int Maxn = 2 * 1e5 + 7;
const int Inf = 1e9 + 7;
int N , q , k;
vector <int> G[Maxn];
int vis[Maxn] , cnt[Maxn] , F[Maxn];
int Dfs(int x , int num){
vis[x]++;
cnt[x] = num + 1;
F[++num] = x;
for(int i = 0 ; i < G[x].size() ; i++){
vis[x] += Dfs(G[x][i] , num);
num += vis[G[x][i]];
}
return vis[x];
}
int main()
{
int x;
scanf(" %d %d",&N , &q);
for(int i = 2 ; i <= N ; i++){
scanf(" %d",&x);
G[x].push_back(i);
}
x = Dfs(1 , 0);
/*
for(int i = 1 ; i <= N ; i++){
printf("#%d = %d %d\n",i , cnt[i] , F[i]);
}
*/
while(q--){
scanf(" %d %d",&x , &k);
if(vis[x] < k){
printf("-1\n");
continue;
}
printf("%d\n",F[cnt[x]+k-1]);
}
return 0;
}