[BZOJ2783] [JLOI2012]树

题目描述

Description

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

Input

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

Output

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

Sample Input

3 3
1 2 3
1 2
1 3

Sample Output

2

HINT

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

题目分析

这题方法有很多啊= =
我们在树上维护一个队列 使得队列里值的总和不超过S
具体操作:维护头尾指针 每次dfs完子树后 把头指针还原回初始状态即可

#include <cstdio>
#include <cstring>
#include <set>
#include <map>
#include <vector>
#include <cmath>
#include <queue>
#include <algorithm>
using namespace std;
int n,m;
int val[100010];
int tot;
int head[100010],to[100010*2],net[100010*2];
void add(int x,int y)
{
    net[++tot]=head[x],head[x]=tot,to[tot]=y;
}
int h,t,ans;
int deep[100010],q[100010];
void dfs(int x)
{
    int temp=h;
    q[++t]=x;
    while(deep[x]-deep[q[h]]>m) h++;
    if(deep[x]-deep[q[h]]==m) ans++;
    for(int i=head[x];i;i=net[i])
            deep[to[i]]=deep[x]+val[to[i]],dfs(to[i]);
    t--,h=temp;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%d",&val[i]);
    for(int x,y,i=1;i<n;i++)
        scanf("%d%d",&x,&y),add(x,y);
    q[1]=1,deep[1]=val[1],h=0,t=0;
    dfs(1);
    printf("%d",ans);
    return 0;
}

发表评论

邮箱地址不会被公开。 必填项已用*标注