题目大意
给出一个
n
n
n 个点构成的森林,有
m
m
m 组询问
每次询问一个点
x
x
x 与多少个点拥有共同的
k
k
k 级祖先
题解
我们稍微转化一下题意:
设
y
y
y 为
x
x
x 的树上
k
k
k 级祖先,那么询问就变成了在
y
y
y 的子树中有多少个点与
y
y
y 的距离为
k
k
k。最后输出时需要减一
首先,我们dfs求出每个点的深度
然后,给每一个点
x
x
x 开一棵线段树,只需要支持单点修改和单点查询。位置
i
i
i 记录
x
x
x 子树中深度为
i
i
i 的点的出现次数
最后询问时,直接查询
y
y
y 的子树中跟
x
x
x 深度相同的节点数(记得减一)
注意要特判
x
x
x 没有
k
k
k 级祖先的情况
朴素复杂度
O
(
n
2
)
\operatorname{O}(n^2)
O(n2)
线段树合并复杂度
O
(
n
log
n
)
\operatorname{O}(n\log n)
O(nlogn)
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int Maxn=100000+10;
const int Maxm=5000000+10;
const int inf=0x3f3f3f3f;
int root[Maxn],head[Maxn];
int nxt[Maxn<<1],to[Maxn<<1];
int f[Maxn][23],c[Maxn];
int sum[Maxm],d[Maxn];
int ls[Maxm],rs[Maxm];
int n,m,edgecnt,idcnt,cnt;
inline int read()
{
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0' && ch<='9')s=(s<<3)+(s<<1)+(ch^48),ch=getchar();
return s*w;
}
inline void add(int x,int y)
{
++edgecnt;
nxt[edgecnt]=head[x];
to[edgecnt]=y;
head[x]=edgecnt;
}
inline void push_up(int x)
{
sum[x]=sum[ls[x]]+sum[rs[x]];
}
inline void modify(int &x,int l,int r,int pos,int v)
{
if(!x)x=++idcnt;
if(l==r)
{
sum[x]+=v;
return;
}
int mid=(l+r)>>1;
if(pos<=mid)modify(ls[x],l,mid,pos,v);
else modify(rs[x],mid+1,r,pos,v);
push_up(x);
}
int merge(int x,int y)
{
if(!x || !y)return x|y;
int cur=++idcnt;
sum[cur]=sum[x]+sum[y];
ls[cur]=merge(ls[x],ls[y]);
rs[cur]=merge(rs[x],rs[y]);
return cur;
}
int query(int x,int l,int r,int pos)
{
if(!x)return 0;
if(l==r)return sum[x];
int mid=(l+r)>>1;
if(pos<=mid)return query(ls[x],l,mid,pos);
else return query(rs[x],mid+1,r,pos);
}
void dfs(int x,int fa)
{
f[x][0]=fa,d[x]=d[fa]+1;
for(int i=1;i<=17;++i)
f[x][i]=f[f[x][i-1]][i-1];
for(int i=head[x];i;i=nxt[i])
{
int y=to[i];
if(y==fa)continue;
dfs(y,x);
root[x]=merge(root[x],root[y]);
}
modify(root[x],1,n,d[x],1);
}
int find(int x,int k)
{
for(int i=17;i>=0;--i)
if(k & (1<<i))x=f[x][i];
return x;
}
int main()
{
// freopen("in.txt","r",stdin);
n=read();
for(int i=1;i<=n;++i)
{
int x=read();
if(!x)c[++cnt]=i;
else add(i,x),add(x,i);
}
for(int i=1;i<=cnt;++i)
dfs(c[i],0);
m=read();
while(m--)
{
int x=read(),k=read();
int pos=find(x,k);
if(!pos)printf("0 ");
else printf("%d ",query(root[pos],1,n,d[x])-1);
}
return 0;
}