ABC202 E,Count Descendants(dfs+二分)
题意:
给出一棵树,然后让你求出树的第x层中有多少节点是y的子树?
思路:
首先我们肯定要统计出每个节点在第几层中.这个统计节点在第几层很容易想到用dfs或者bfs,但是我们建完树之后那.
然后就是如何记录那个节点是其他节点的子树?
我们可以用倍增的方法,但是如果一条链太长就行了,就会直接爆.然后用到一个新知识,get了时间戳.顾名思义就是单位时间,就是记录每一刻的时间.
首先我们为了方便叙述,用in[]数组表示进入这个点(子树)的时间,用out[]数组表示出去这个点(子树)的时间.
比如V是U的子树,那么我们就知道.\(in[u]<in[v]<out[v]<out[u]\).所以我们发现,in和out直接的所有范围内的时间都是该点的子树,这就把数据连续话,就让我们很好分析这个谁是谁的子树了,我们只需要比较时间即可,又因为,时间是连续的,所以我们就可以利用二分某一层的思想,来得到,该点在这一层有多少节点.
ll n,m,tim;
int in[maxn],out[maxn];
bool vis[maxn];/// biaoji
vector<int> v[maxn],e[maxn];
void dfs(int x,int num){
vis[x]=true;
in[x]=++tim;
e[num].push_back(in[x]);
for(int i=0;i<(int)v[x].size();i++){
ll y=v[x][i];
if(vis[y]==false){
dfs(y,num+1);
}
}
out[x]=++tim;
}
void solve()
{
scanf("%lld",&n);
for(int i=2;i<=n;i++){
int x;
scanf("%d",&x);
v[x].push_back(i);
v[i].push_back(x);
}
dfs(1,1);
scanf("%lld",&m);
while(m--){
int x,y;
scanf("%d%d",&x,&y);
y++;
int l=lower_bound(e[y].begin(),e[y].end(),in[x])-e[y].begin();
int r=upper_bound(e[y].begin(),e[y].end(),out[x])-e[y].begin();
printf("%d\n",r-l);
}
}