题:https://codeforces.com/problemset/problem/208/E
题意:给定树,问m个询问,每个询问vi,pi,要查询和vi有pi级相同祖先的对数;
分析:支持离线且没修改,考虑dsu,,因为树每个节点向上的路径是一定的,所以我们吧询问点vi转移到pi级祖先上,然后问题就变为我们熟悉的找子树中相同高度的个数
#include<bits/stdc++.h> #include<tr1/unordered_map> using namespace std; typedef long long ll; #define pb push_back const int M=1e5+5; struct node{ int p,id; }; vector<node>q[M]; vector<int>g[M]; int n,grand[M][20],sz[M],deep[M],cnt[M],root,s,ans[M],son[M],vis[M]; void dfs1(int u){ sz[u]=1; for(int i=1;i<=s;i++){ grand[u][i]=grand[grand[u][i-1]][i-1]; if(!grand[u][i]) break; } for(auto v:g[u]){ if(v!=grand[u][0]){ grand[v][0]=u; deep[v]=deep[u]+1; dfs1(v); sz[u]+=sz[v]; if(sz[son[u]]<sz[v]) son[u]=v; } } } void init(){ s=floor(log(1.0*n)/log(2.0)); deep[0]=0; dfs1(root); } void update(int u,int fa,int k){ cnt[deep[u]]+=k; for(auto v:g[u]) if(v!=fa&&!vis[v]) update(v,u,k); } void dfs2(int u,int fa,int sign){ for(auto v:g[u]){ if(v!=fa&&v!=son[u]) dfs2(v,u,0); } if(son[u]) dfs2(son[u],u,1),vis[son[u]]=1; update(u,fa,1); for(auto i:q[u]){ int id=i.id; int p=i.p; ans[id]=cnt[p+deep[u]]-1; } if(son[u]) vis[son[u]]=0; if(!sign) update(u,fa,-1); } int main(){ scanf("%d",&n); for(int x,i=1;i<=n;i++){ scanf("%d",&x); g[i].pb(x); g[x].pb(i); } init(); int m; scanf("%d",&m); for(int i=1;i<=m;i++){ int x,y,z; scanf("%d%d",&x,&y); z=y; for(int j=18;j>=0;j--){ int tmp=1<<j; while(y-tmp>=0&&grand[x][j]!=0){ x=grand[x][j]; y-=tmp; } } if(y==0) q[x].pb(node{z,i}); } dfs2(0,-1,0); for(int i=1;i<=m;i++) printf("%d ",ans[i]); return 0; }
原文:https://www.cnblogs.com/starve/p/12657111.html