题目链接:https://codeforces.com/problemset/problem/208/E
题目大意:给你一片森林,再给q次询问:每次x y:询问x的有级祖先有多少个儿子和x处于同一层(排除x节点外)。
思路:我们把查询改为x的k级祖先y在deep[x]层有多少个子节点。用LCA处理一下,然后启发式合并可以了。
#include <bits/stdc++.h> using namespace std; vector<int> G[100005]; int c[100005], ans[100005], vis[100005]; struct LCA{ int d[100005], fa[100005][22], lg[100005]; void init(int n, int root){//预处理 if(!lg[10]){ for(int i = 1; i <= n; ++i){ lg[i] = lg[i-1] + (1 << lg[i-1] == i); } } dfs(root, 0); } void dfs(int now, int father){ vis[now]=1; fa[now][0]=father; d[now]=d[father]+1; for(int i=1; i<=lg[d[now]]; ++i){ fa[now][i]=fa[fa[now][i-1]][i-1]; } for(auto x: G[now]){ if(x!=father){ dfs(x, now); } } } int klca(int x, int y){//第k级祖先(自己第0级) for(int i=30; i>=0; i--){ if(y&(1<<i)){ x=fa[x][i]; } } return x; } }lca; vector<pair<int, int> > q[100005]; int siz[100005], dfn[100005], son[100005], d[100005], T=0; void dfs(int u, int deep){ vis[u]=1; siz[u]=1, dfn[u]=++T; d[T]=deep; for(auto x: G[u]){ dfs(x, deep+1); siz[u]+=siz[x]; son[u]=siz[x]>siz[son[u]]?x:son[u]; } } void DSU(int u, int k){ vis[u]=1; for(auto x: G[u]){ if(x!=son[u]){ DSU(x, 0); } } if(son[u]) DSU(son[u], 1); for(auto x: G[u]){ if(x!=son[u]){ for(int i=0; i<siz[x]; i++){ int now=dfn[x]+i; c[d[now]]++; } } } c[d[dfn[u]]]++; for(auto x: q[u]){ int k=x.first, pos=x.second; ans[pos]=c[k+d[dfn[u]]]; } if(!k){ for(int i=0; i<siz[u]; ++i){ int now=dfn[u]+i; c[d[now]]=0; } } } int main(){ int n, x, k; scanf("%d", &n); for(int i=1; i<=n; i++){ scanf("%d", &x); if(x){ G[x].push_back(i); } } for(int i=1; i<=n; i++){ if(!vis[i]){ lca.init(n, i); } } memset(vis, 0, sizeof(vis)); int Q; scanf("%d", &Q); for(int i=1; i<=Q; i++){ scanf("%d%d", &x, &k); int pos=lca.klca(x, k); q[pos].push_back({k, i}); } for(int i=1; i<=n; i++){ if(!vis[i]){ dfs(i, 0); } } memset(vis, 0, sizeof(vis)); for(int i=1; i<=n; i++){ if(!vis[i]){ DSU(i, 0); // for(int i=1; i<=5; i++){ // cout<<i<<" "<<c[i]<<endl; // } } } for(int i=1; i<=Q; i++){ printf("%d ", (ans[i]?ans[i]-1:0)); } printf("\n"); return 0; } /* 6 0 1 1 0 4 4 1 5 1 */