传送门

题意

给你一片森林,每次询问一个点与多少个点拥有共同的K级祖先


当我们遍历完 u u u的子树时,应该解决所有和 u u u子树相关的询问

所以需要转化问题

就是对于一个询问点 u u u k k k级祖先

直接把询问加到 k k k级祖先上去,这样就是求每个子树内深度等于 u u u的有多少个节点

开始我蠢了,在 d s u dsu dsu的过程计数的是相对深度

但是重儿子合并到父亲节点的时候这个相对深度就变化了啊!!还找了好久 b u g . . . bug... bug...

#include <bits/stdc++.h>
using namespace std;
const int maxn = 4e5+10;
struct edge{
	int to,nxt;
}d[maxn]; int head[maxn],cnt=1;
void add(int u,int v){
	d[++cnt] = (edge){v,head[u]},head[u] = cnt;
}
struct query{
	int to,nxt,id,ans;
	bool operator < (const query&tmp )	const{
		return id<tmp.id;
	}
}d1[maxn]; int head1[maxn],cnt1=1;
void addquery(int u,int k,int id){
	d1[++cnt1] = (query){k,head1[u],id,0},head1[u] = cnt1;
}
int siz[maxn],son[maxn],dep[maxn],fa[maxn][22],n,isok[maxn],deep[maxn];
void dfs(int u,int ffa)
{
	siz[u] = 1; fa[u][0] = ffa; deep[u] = deep[ffa]+1;
	for(int i=1;i<=18;i++)
		fa[u][i] = fa[ fa[u][i-1] ][i-1];
	for(int i=head[u];i;i=d[i].nxt )
	{
		int v = d[i].to;
		if( v==ffa )	continue;
		dfs(v,u);
		siz[u] += siz[v];
		if( siz[v]>siz[son[u]] )	son[u] = v;
	}
}
int SON;
void insert(int u,int ffa,int val)
{
	dep[ deep[u] ]+=val;
	for(int i=head[u];i;i=d[i].nxt )
	{
		int v = d[i].to;
		if( v==ffa || v==SON )	continue;
 		insert( v,u,val);
	}
}
void dsu(int u,int ffa,int type)
{
	for(int i=head[u];i;i=d[i].nxt )
	{
		int v = d[i].to;
		if( v==son[u]||v==ffa )	continue;
		dsu(v,u,0);//不保存 
	}
	if( son[u] )	dsu(son[u],u,1),SON = son[u];
	insert( u,ffa,1 ); 
	SON = 0;
	for(int i=head1[u];i;i=d1[i].nxt )
	{
		d1[i].ans = dep[ deep[d1[i].to] ];
	}
	if( !type )	insert( u,ffa,-1 );
}
int kth(int x,int k)
{
	for(int i=18;i>=0;i--)
		if( k>=(1<<i) )	k-=(1<<i), x = fa[x][i];
	return x;
}
int main()
{
	cin >> n;
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&isok[i]);
		if( isok[i] )
			add( isok[i],i ); add( i,isok[i] );
	}
	for(int i=1;i<=n;i++)
		if( !isok[i] )	dfs(i,0);
	int q; scanf("%d",&q);
	for(int i=1;i<=q;i++)
	{
		int u,k; scanf("%d%d",&u,&k);
		addquery( kth(u,k),u,i );
	}
	for(int i=1;i<=n;i++)
		if( !isok[i] )	dsu(i,0,0);
	sort( d1+2,d1+2+q );
	for(int i=2;i<=q+1;i++)
		printf("%d ",max( 0,d1[i].ans-1) );
}