1 条题解
-
0
考虑先离线,再处理答案。
考虑一个询问与 有相同 级祖先的点,等于询问在 的 级祖先的点的子树中与 深度相同的点的个数。
直接用线段树合并维护,一个点的权值就是深度。
代码
#include<bits/stdc++.h> #define mid (l+r>>1) using namespace std; const int N=1e5+5; int n,f[N][25],m,ans[N],dep[N],cnt,rt[N]; struct segtree{int l,r,sum;}tr[N*40]; vector<int> e[N]; vector<pair<int,int> > que[N]; void dfs(int x){ for(int i=1;i<=20;i++)f[x][i]=f[f[x][i-1]][i-1]; for(int y:e[x]){ dep[y]=dep[x]+1; dfs(y); } } void add(int &p,int l,int r,int x,int z){ if(!p)p=++cnt; if(l==r){ tr[p].sum+=z; return; } if(x<=mid)add(tr[p].l,l,mid,x,z); else add(tr[p].r,mid+1,r,x,z); } void he(int &p,int q,int l,int r){ if(!p||!q){p=q+p;return;} if(l==r){ tr[p].sum+=tr[q].sum; return; } he(tr[p].l,tr[q].l,l,mid); he(tr[p].r,tr[q].r,mid+1,r); } int ask(int p,int l,int r,int x){ if(!p)return 0; if(l==r)return tr[p].sum; if(x<=mid)return ask(tr[p].l,l,mid,x); else return ask(tr[p].r,mid+1,r,x); } int jump(int x,int y){ for(int i=0;i<=20;i++)if(y&(1<<i))x=f[x][i]; return x; } void dfs1(int x){ for(int y:e[x]){ dfs1(y); he(rt[x],rt[y],1,n); } for(auto i:que[x])ans[i.second]=ask(rt[x],1,n,dep[x]+i.first)-1; add(rt[x],1,n,dep[x],1); } int main(){ scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d",&f[i][0]); if(f[i][0])e[f[i][0]].push_back(i); } for(int i=1;i<=n;i++)if(!f[i][0])dep[i]=1,dfs(i); scanf("%d",&m); for(int i=1;i<=m;i++){ int x,K; scanf("%d%d",&x,&K); int t=jump(x,K); if(t)que[t].emplace_back(K,i); } for(int i=1;i<=n;i++)if(!f[i][0])dfs1(i); for(int i=1;i<=m;i++)printf("%d ",ans[i]); }
- 1
信息
- ID
- 2
- 时间
- 2000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 4
- 已通过
- 3
- 上传者