bzoj 2783 JLOI2012 树
bzoj2783 JLOI2012 树
Description
在这个问题中,给定一个值S和一棵树。在树的每个节点有一个正整数,问有多少条路径的节点总和达到S。路径中节点的深度必须是升序的。假设节点1是根节点,根的深度是0,它的儿子节点的深度为1。路径不必一定从根节点开始。
Input
第一行是两个整数N和S,其中N是树的节点数。
第二行是N个正整数,第i个整数表示节点i的正整数。
接下来的N-1行每行是2个整数x和y,表示y是x的儿子。
Output
输出路径节点总和为S的路径数量。
参考了神犇的博客,可以用dfs加set过,这么打比某些方法要方便一些.我们记录下一条链的前缀和,把它放进set里面,对于当前搜到的点x,如果set里面有一个元素等于sum[x]-S,那么表示从根到x节点的和减去那个元素所对应的点的和就是S.开始的时候要加入元素0.
代码如下
#include <set>
#include <cstdio>
#include <algorithm>
using namespace std;
static const int maxm=1e6+10;
multiset<int>Set;
int fst[maxm],nxt[maxm],to[maxm],sum[maxm],val[maxm];
int S,cnt,n,x,y,ans;
void ins(int f,int t){
nxt[++cnt]=fst[f];
fst[f]=cnt;
to[cnt]=t;
}
void dfs(int x){
if(Set.find(sum[x]-S)!=Set.end())ans++;
Set.insert(sum[x]);
for(int u=fst[x];u;u=nxt[u]){
int v=to[u];
sum[v]=sum[x]+val[v];
dfs(v);
}
Set.erase(Set.find(sum[x]));
}
int main(){
scanf("%d%d",&n,&S);
for(int i=1;i<=n;i++)scanf("%d",&val[i]);
for(int i=1;i<n;i++)
scanf("%d%d",&x,&y),ins(x,y);
sum[1]=val[1];Set.insert(0);
dfs(1);
printf("%d\n",ans);
return 0;
}