树(C++)

题面

题目描述

给定一棵有根树,树上一共有 n 个节点,节点的编号是 1∼n,其中根节点的编号为 1,每个节点有一个值 ai,请你求出对于每个节点,它的子树中有多少个节点到它的最短 距离不超过 ai。

输入格式

第一行一个整数 n 表示树的节点个数。
第二行 n 个整数 a1,a2,⋅⋅⋅,an 用空格隔开。
接下来 n−1 行每行两个整数 u,v 表示节点 u 和节点 v 存在一条边。

输出格式

输出一行 n 个整数表示答案,用空格隔开。

输入输出样例

输入 #1复制

3
1 1 1
1 2
1 3

输出 #1复制

2 0 0

输入 #2复制

9
2 3 3 3 3 3 3 3 3
1 2
1 3
3 4
3 5
4 6
4 7
5 8
8 9

输出 #2复制

4 0 6 2 2 0 0 1 0

说明/提示

对于所有测试点:1≤n≤10^5,1≤ai≤20。

测试点编号n≤
1∼510
6∼1010^3
11∼2010^5

思路 

这道题我们先看一下数据大小,n≤10^5,但是 ai≤20。很显然,我们可以利用这个 “bug” 只要循环n次,每次 dfs  a[ i ] 也是不会超的。但因为要求计算子树上的权值,所以要先记录 father 数组。

这时候很多人就会被题目套路(包括我),以为根节点为 1 就说明每条输入边的第一个值就是 父亲,第二个就是孩子。题目又没告诉你这条信息!

所以我们还是要先 dfs 一遍 father,再开始计算。

时间复杂度 O(n*a)

函数代码

void dfs1(int u){
	for(auto v:e[u]){
		if(v!=fa[u]){
			fa[v]=u;
			dfs1(v);
		}
	}
} 
void dfs(int u,int f,int s,int step){
	ans[u]=1;
	if(step>s){
		ans[u]=0;
		return;
	}
	if(step==s||e[u].size()==1)return;
	for(int i=0;i<e[u].size();i++){
		int v=e[u][i];
		if(v!=f){
			dfs(v,u,s,step+1);
			ans[u]+=ans[v];
		}
	}
}

主函数代码

//	freopen("tree.in","r",stdin);
//	freopen("tree.out","w",stdout);
	cin>>n;
	for(int i=1;i<=n;i++)cin>>a[i];
	for(int i=1;i<n;i++){
		int u,v;
		cin>>u>>v;
		e[u].push_back(v);
		e[v].push_back(u);
	}
	dfs1(1);
	for(int i=1;i<=n;i++){
		dfs(i,fa[i],a[i],0);
		cout<<ans[i]-1<<' ';
	}

唉,真是太可惜了(加上这个函数我肯定就能冲比赛第一了),比赛时只拿了个鸭蛋 。

好了,这篇讲解还是比较短的,因为题目简单,虽然我们班一个同学都没做出来

如果认为讲得好的话,记得点个关注,谢谢!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值