BZOJ 2783: [JLOI2012]树

来源:互联网 发布:三狼三羊过河 算法 编辑:程序博客网 时间:2024/05/18 02:37

Description

把一个正整数分成一列连续的正整数之和。这个数列必须包含至少两个正整数。你需要求出这个数列的最小长度。如果这个数列不存在则输出-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。

分析

本来我是想用一颗平衡数来找前驱的。结果被人提醒了一发,发现可以用个栈来维护,因为全是正的,所以直接二分,满足单调性。

代码

#include <bits/stdc++.h>#define N 100005struct NOTE{    int to,next;}e[N*2];int head[N];int st[N],Q[N],sum[N];int top,ans;int s,n;int cnt=0;void add(int x,int y){    e[++cnt].to=y;e[cnt].next=head[x];head[x]=cnt;    e[++cnt].to=x;e[cnt].next=head[y];head[y]=cnt;}void dfs(int dep,int now,int root){    st[++top]=now;    int need=std::lower_bound(st+1,st+top+1,now-s)-st;    if(st[need]+s==now && need>0 && need<=top)        ans++;    for(int i=head[dep];i;i=e[i].next)    {        if(e[i].to==root)            continue;        dfs(e[i].to,now+sum[e[i].to],dep);      }    top--;}int main(){    scanf("%d%d",&n,&s);    for(int i=1;i<=n;i++)        scanf("%d",&sum[i]);    for(int i=1;i<n;i++)    {        int x,y;        scanf("%d%d",&x,&y);        add(x,y);    }       st[++top]=0;    dfs(1,sum[1],0);    printf("%d\n",ans);}
0 0
原创粉丝点击