CodeForces - 208E Blood Cousins(树上倍增+二分)
题意:好几棵树,询问祖先为点i往上的第k个,且深度与点i相同点有多少个
解法:找点i的祖先很好找,如果这时我们搜索暴力,肯定会超时,所以就想到了二分优化,先预处理dfs序,得出新的编号,并开一个vector分别按深度记录下来,然后在查询祖先为t深度为h的点的个数时,只需要在vector第h层里二分,统计L[t]到R[t]之间有多少个点,要除去i点本身,所以减一就是结果.
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
const int maxn=1e5+5;
vector<int> v[maxn],root,node[maxn];
int deep[maxn],fa[maxn][22];
int sum[maxn];
int cnt=0;
int L[maxn],R[maxn];
void dfs(int x){
for(int i=1;i<=21;i++){
if(fa[x][i-1]) fa[x][i]=fa[fa[x][i-1]][i-1];
else break;
}
L[x]=++cnt;
node[deep[x]].push_back(cnt);
for(int i=0;i<v[x].size();i++){
int t=v[x][i];
if(t!=fa[x][0]){
fa[t][0]=x;
deep[t]=deep[x]+1;
dfs(t);
}
}
R[x]=cnt;
}
int solve(int x,int k){
int fat=x;
for(int i=0;i<=21;i++)
if((1<<i)&k)
fat=fa[fat][i];
if(fat==0) return 0;
int a=L[fat],b=R[fat];
int h=deep[x];
int l=lower_bound(node[h].begin(),node[h].end(),a)-node[h].begin();
int r=upper_bound(node[h].begin(),node[h].end(),b)-node[h].begin()-1;
return r-l;
}
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
int x;
scanf("%d",&x);
if(x==0) root.push_back(i);
else v[x].push_back(i);
}
for(int i=0;i<root.size();i++)
dfs(root[i]);
int m,x,y;
scanf("%d",&m);
scanf("%d%d",&x,&y);
printf("%d",solve(x,y));
m--;
while(m--){
scanf("%d%d",&x,&y);
printf(" %d",solve(x,y));
}
printf("\n");
return 0;
}