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);
	}
}
posted @ 2021-07-23 17:34  `KingZhang`  阅读(36)  评论(0编辑  收藏  举报