第一行是两个整数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\n",ans); return 0; }