无任何高级数据结构。

本题分为两部分:

  1. 一部分是求出树上 \(k\) 级祖先,直接倍增跳就可以。

  2. 另一部分是求出树上 \(k\) 级子孙的数量,这一部分比较复杂。

    首先一个点的 \(k\) 级子孙的深度显然都是一样的,因为是在同一子树内,所以,如果我们把 \(dep\) 为 \(x\) 的点的 \(dfs\) 序从小到大存起来就会发现它们是连续的。

    把它们存起来之后,问题就变成了统计一个单调递增的序列中数值在 \(l\sim r\) 内的数的个数。这个问题我们可以二分解决,我们可以二分出小于 \(r\) 的数的最大的位置,求出可行答案的右端点,再二分出左端点就可以了。

#include<bits/stdc++.h>
#define log(a) cerr<<"\033[32m[DEBUG] "<<#a<<'='<<(a)<<" @ line "<<__LINE__<<"\033[0m"<<endl
#define LL long long
#define SZ(x) ((int)x.size()-1)
#define ms(a,b) memset(a,b,sizeof a)
#define F(i,a,b) for(int i=(a);i<=(b);++i)
#define DF(i,a,b) for(int i=(a);i>=(b);--i)
using namespace std;
inline int read(){char ch=getchar(); int w=1,c=0;
	for(;!isdigit(ch);ch=getchar()) if (ch=='-') w=-1;
	for(;isdigit(ch);ch=getchar()) c=(c<<1)+(c<<3)+(ch^48);
	return w*c;
}
template<typename T>inline void write(T x){
    unsigned long long y=0;T l=0;
    if(x<0)x=-x,putchar(45);
    if(!x){putchar(48);return;}
    while(x){y=y*10+x%10;x/=10;l++;}
    while(l){putchar(y%10+48);y/=10;l--;}
}
template<typename T>inline void writeln(T x){write(x);puts("");}
template<typename T>inline void writes(T x){write(x);putchar(32);}
const int N=1e6+10;
int fa[10][N],dep[N],cnt,l[N],r[N],h[N],a[N],t[N],tot,hd[N],nxt[N],to[N];
inline void add(int x,int y){
	to[++tot]=y;
	nxt[tot]=hd[x];
	hd[x]=tot;
}
void dfs(int x){
	l[x]=++cnt;
	a[x]=++h[dep[x]];
	for(int i=hd[x];i;i=nxt[i])dfs(to[i]);
	r[x]=cnt;
}
signed main(){
	int n=read();
	F(i,1,n){
		fa[0][i]=read();
		if(!fa[0][i]){
			dep[i]=1;
			continue;
		}
		add(fa[0][i],i);
		dep[i]=dep[fa[0][i]]+1;
		F(j,1,9)fa[j][i]=fa[j-1][fa[j-1][fa[j-1][fa[j-1][i]]]];
	}
	F(i,1,n)
		if(!fa[0][i])dfs(i);
	F(i,2,n)h[i]+=h[i-1];
	F(i,1,n)t[h[dep[i]-1]+a[i]]=l[i];
	int q=read();
	while(q--){
		int x=read(),k=read(),z=dep[x];
		DF(i,9,0){
			int z=(1<<(i<<1));
			if(k>=z)k-=z,x=fa[i][x];
			if(k>=z)k-=z,x=fa[i][x];
			if(k>=z)k-=z,x=fa[i][x];
		}
		int l=h[z-1],r=h[z]+1;
		while(l+1<r){
			int mid=(l+r)>>1;
			if(mid<0)break;
			if(t[mid]<::l[x])l=mid;
			else r=mid;
		}
		int kl=l+1,kr=h[z]+1;
		while(kl+1<kr){
			int kmid=(kl+kr)>>1;
			if(t[kmid]<=::r[x])kl=kmid;
			else kr=kmid;
		}
		writes(kl-l-1);
	}
	return 0;
}