链接:http://www.codeforces.com/problemset/problem/208/E
题意:给你一个森林,m个询问:v,p
求有多少个点(除v外) 与 v的第p个祖先相同
这个题首先要解决找某个点的第p个祖先的问题,可以采用倍增法
记录一个二维数组p[u][i]表示u的第2^i个祖先,那么通过这个数组我们就可以知道u的上面任意深度(相对于u)祖先是谁(巧妙的利用二进制)
具体求法和用法见下,还可以找LCA的
/* 2^17=131072; 2^18=262144; */ const int POW = 18; void dfs(int u,int fa){ d[u]=d[fa]+1; p[u][0]=fa; for(int i=1;i<POW;i++) p[u][i]=p[p[u][i-1]][i-1]; int sz=edge[u].size(); for(int i=0;i<sz;i++){ int v=edge[u][i]; if(v==fa) continue; dfs(v,u); } } int lca( int a, int b ){ if( d[a] > d[b] ) a ^= b, b ^= a, a ^= b; if( d[a] < d[b] ){ int del = d[b] - d[a]; for( int i = 0; i < POW; i++ ) if(del&(1<<i)) b=p[b][i]; } if( a != b ){ for( int i = POW-1; i >= 0; i-- ) if( p[a][i] != p[b][i] ) a = p[a][i] , b = p[b][i]; a = p[a][0], b = p[b][0]; } return a; }
假设vp是v的p祖先,那么v 的 p Cousins就是时间戳位于vp的两个时间戳之间深度为dep【v】
的点的个数
#include<cstdio> #include<cstring> #include<vector> #include<algorithm> using namespace std; const int maxn = 100010; vector<int> g[maxn]; vector<int> edge[maxn]; vector<int> rt; bool vis[maxn]; int n,m,dfn; int in[maxn],out[maxn]; int dep[maxn],p[maxn][18]; int depth; void dfs(int u,int fa){ vis[u]=true; in[u]=dfn++; //printf("in[%d]=%d\n",u,in[u]); dep[u]=dep[fa]+1; g[dep[u]].push_back(dfn); p[u][0]=fa; for(int i=1;i<18;i++) p[u][i]=p[p[u][i-1]][i-1]; int sz=edge[u].size(); for(int i=0;i<sz;i++){ int v=edge[u][i]; if(v==fa) continue; dfs(v,u); } out[u]=dfn++; //printf("out[%d]=%d\n",u,out[u]); } int solve(int tfn,int d){ int l=0,r=g[d].size()-1,best=-1; while(l<=r){ int m=l+r>>1; if(g[d][m]<=tfn){ l=m+1; best=m; } else r=m-1; } return best+1; } int find(int v,int pp){ for(int i=0;i<18;i++) if(pp&(1<<i)) v=p[v][i]; return v; } int ans[maxn]; int main() { while(scanf("%d",&n)!=EOF) { int fa,v,pp; rt.clear(); memset(p,0,sizeof(p)); memset(dep,0,sizeof(dep)); for(int i=0;i<=n;i++) edge[i].clear(),g[i].clear(); for(int i=1;i<=n;i++) { scanf("%d",&fa); if(fa==0) rt.push_back(i); else edge[fa].push_back(i); } dfn=0;depth=0; for(int i=0;i<rt.size();i++) depth=0,dfs(rt[i],0); scanf("%d",&m); for(int i=0;i<m;i++) { scanf("%d%d",&v,&pp); int vp=find(v,pp); if(!vp) ans[i]=0; else { ans[i]=solve(out[vp],dep[v])-solve(in[vp]-1,dep[v])-1; } } for(int i=0;i<m;i++) printf("%d ",ans[i]); puts(""); } return 0; }