无任何高级数据结构。
本题分为两部分:
-
一部分是求出树上 \(k\) 级祖先,直接倍增跳就可以。
-
另一部分是求出树上 \(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;
}