[洛谷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)的超小范围=暴力满分