[洛谷P3252] [JLOI2012] 树

[洛谷P3252] [JLOI2012] 树

给定一个值(S)和一棵树。在树的每个节点有一个正整数,问有多少条路径的节点总和达到(S)
 路径中节点的深度必须是升序的。假设节点(1)是根节点,根的深度是(0),它的儿子节点的深度为(1)
 路径不必一定从根节点开始。

Input

第一行是两个整数(N)(S),其中(N)是树的节点数。
 第二行是(N)个正整数,第(i)个整数表示节点(i)的正整数。
 接下来的(N-1)行每行是(2)个整数(x)(y),表示(y)(x)的儿子。

Output

输出路径节点总和为(S)的路径数量。

Example

输入 #1

(3) (3)
(1) (2) (3)
(1) (2)
(1) (3)

输出 #1

(2)

Scoring

对于(100%)数据,(N≤100000),所有权值以及(S)都不超过(1000)

注意:是总和刚好为(S),不是(≥S)

刚开始审题看成(≥S)了orz

咱也不会啥高端做法,暴力。

盲猜权值无负数,这样的话选一个点,往下搜,搜到大于(S)就return,刚好等于(S)就ans++

原本的错误想法:期望复杂度(O(nlogn)),数据很水,没有链,不会卡成(O(n^2))

更正:下午讲题的时候whx大佬给出了正确的最差复杂度(O(NS)),因为权值大于(0),就算每个节点都是(1)它最多也只会加(S)次,所以不会爆掉。
果然还是太菜了

代码:

#include<bits/stdc++.h>
using namespace std;

int n, s, x, y, cnt;
int v[100005];
int fa[100005];
vector <int> p[100005];

void dfs(int pl, int sum) {
	sum += v[pl];
	if (sum > s) return;
	if (sum == s) {cnt++; return;}
	for (int i = 0; i < p[pl].size(); i++) {
		if (p[pl][i] != fa[pl])
			dfs(p[pl][i], sum);
	}
}

int main() {
	scanf("%d %d", &n, &s);
	for (int i = 1; i <= n; i++) scanf("%d", &v[i]);
	for (int i = 1; i < n; i++) {
		scanf("%d %d", &x, &y);
		fa[y] = x; 
		p[x].push_back(y);
	}
	for (int i = 1; i <= n; i++) dfs(i, 0);
	printf("%d", cnt);
	return 0;
}

总结:

没有非正数+(S)的超小范围=暴力满分

原文地址:https://www.cnblogs.com/Sheffield/p/13452133.html