思路:
1.询问一个点与多少个点拥有共同的级祖先,可以理解为一个点的级祖先有多少个级儿子
即有多少深度为的孩子,最后答案别忘了 ,因为把自己也算了在内
2.求出相关的点的级祖先可以用求的倍增法
3.将每次查询用容器存储,方便离线操作
4.题目给的是森林,需要存每颗树的根节点
复杂度:
MyCode:
#include<bits/stdc++.h> using namespace std; const int maxn=1e5+7,maxm=1e5+7; typedef long long ll; inline ll read(){ ll s = 0, w = 1; char ch = getchar(); while (ch < 48 || ch > 57) { if (ch == '-') w = -1; ch = getchar(); } while (ch >= 48 && ch <= 57) s = (s << 1) + (s << 3) + (ch ^ 48), ch = getchar(); return s * w; } int head[maxn],Next[maxm],to[maxm],tot; void add(int x,int y) { to[++tot]=y; Next[tot]=head[x]; head[x]=tot; } int size[maxn],son[maxn],dep[maxn]; int cnt[maxn],ans[maxn],dp[maxn][20]; bool vis[maxn]; int que[maxn]; #define x first #define y second vector<pair<int,int> >query[maxn]; void dfs1(int x,int f) { size[x]=1; dep[x]=dep[f]+1; dp[x][0]=f; for(int i=1;i<18;++i) if(dp[x][i-1]!=-1) dp[x][i]=dp[dp[x][i-1]][i-1]; for(int i=head[x],v;i;i=Next[i]) { v=to[i]; dfs1(v,x); size[x]+=size[v]; if(size[son[x]]<size[v]) son[x]=v; } } void calc(int x) { cnt[dep[x]]+=1; for(int i=head[x],v;i;i=Next[i]) { v=to[i]; if(vis[v]) continue; calc(v); } } void delet(int x) { cnt[dep[x]]-=1; for(int i=head[x],v;i;i=Next[i]) { v=to[i]; delet(v); } } void dfs2(int x,bool opt) { for(int i=head[x],v;i;i=Next[i]) { v=to[i]; if(son[x]==v) continue; dfs2(v,false); } if(son[x]) { dfs2(son[x],true); vis[son[x]]=true; } calc(x); int size=query[x].size(); if(size) { for(int i=0;i<size;++i) ans[query[x][i].x]=cnt[query[x][i].y]-1; } if(son[x]) vis[son[x]]=false; if(!opt) delet(x); } int main() { int n=read(),top=0; memset(dp,-1,sizeof dp); for(int i=1,u;i<=n;++i) { u=read(); if(u) add(u,i); else que[++top]=i; } int m=read(); for(int i=1;i<=top;++i) dfs1(que[i],0); for(int i=1,a,k,tmp;i<=m;++i) { a=read(),k=read(); for(int i=17;i>=0;--i) if((1<<i)&k) a=dp[a][i]; query[a].push_back(make_pair(i,dep[a]+k)); } for(int i=1;i<=top;++i) dfs2(que[i],false); for(int i=1;i<=m;++i) printf("%d ",ans[i]); return 0; }