bzoj2783 树

第一行是两个整数N和S,其中N是树的节点数。

第二行是N个正整数,第i个整数表示节点i的正整数。

接下来的N-1行每行是2个整数x和y,表示y是x的儿子。

输出格式:

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

 

输入样例:

输出样例:

3 3

1 2 3

1 2

1 3

2

 

数据范围:

对于30%数据,N≤100;

对于60%数据,N≤1000;

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

倍增预处理出每个节点向上走2^k步到达的点和权值和,对每个点二分向上能走(权值和小于S)的距离

#include<cstdio>
inline int input(){
    int x=0,c=getchar();
    while(c>57||c<48)c=getchar();
    while(c>47&&c<58)x=x*10+c-48,c=getchar();
    return x;
}
const int N=100055;
int n,S,ans=0;
int vs[20][N],fa[20][N];
int main(){
    n=input();S=input();
    for(int i=1;i<=n;i++)vs[1][i]=input();
    for(int i=1,a,b;i<n;i++){
        a=input();b=input();
        fa[1][b]=a;
    }
    for(int t=1;t<19;t++){
        for(int i=1;i<=n;i++){
            int f=fa[t][i];
            fa[t+1][i]=fa[t][f];
            vs[t+1][i]=vs[t][f]+vs[t][i];
        }
    }
    for(int i=1;i<=n;i++){
        int s=S,w=i;
        for(int k=18;k;k--){
            int f=fa[k][w];
            if(!f)continue;
            if(vs[k][w]<s)s-=vs[k][w],w=f;
        }
        if(s==vs[1][w])++ans;
    }
    printf("%d
",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/ccz181078/p/5499139.html