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
",ans);
    
    return 0;
}

点我进入AC通道

原文地址:https://www.cnblogs.com/Exbilar/p/6764435.html