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