1. 程式人生 > >[JLOI2012]樹

[JLOI2012]樹

str -m ostream tro fin 升序 深度 col next

題目描述

在這個問題中,給定一個值S和一棵樹。在樹的每個節點有一個正整數,問有多少條路徑的節點總和達到S。路徑中節點的深度必須是升序的。假設節點1是根節點,根的深度是0,它的兒子節點的深度為1。路徑不必一定從根節點開始。

輸入輸出格式

輸入格式:

第一行是兩個整數N和S,其中N是樹的節點數。 第二行是N個正整數,第i個整數表示節點i的正整數。 接下來的N-1行每行是2個整數x和y,表示y是x的兒子。

輸出格式:

輸出路徑節點總和為S的路徑數量。

輸入輸出樣例

輸入樣例#1:
3 3
1 2 3
1 2
1 3
輸出樣例#1:
2

說明

對於100%數據,N<=100000,所有權值以及S都不超過1000。

遍歷一遍,將根到當前節點路徑上的所有的點的樹上前綴和壓入棧中。

查找時二分棧即可。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<set>
 6 using namespace std;
 7 struct Node
 8 {
 9   int next,to;
10 }edge[200001];
11 int num,head[100001];
12 int S[100001],top,sum[100001],val[100001
],ans,n,s; 13 int fa[100001]; 14 void add(int u,int v) 15 { 16 num++; 17 edge[num].next=head[u]; 18 head[u]=num; 19 edge[num].to=v; 20 } 21 bool find(int x) 22 { 23 int l=0,r=top; 24 while (l<=r) 25 { 26 int mid=(l+r)/2; 27 if (S[mid]==x) return 1; 28 if (S[mid]>x) r=mid-1
; 29 else l=mid+1; 30 } 31 return 0; 32 } 33 void dfs(int x) 34 {int i; 35 sum[x]=sum[fa[x]]+val[x]; 36 S[++top]=sum[x]; 37 if (find(sum[x]-s)) ans++; 38 for (i=head[x];i;i=edge[i].next) 39 { 40 int v=edge[i].to; 41 dfs(v); 42 } 43 top--; 44 } 45 int main() 46 {int i,u,v; 47 cin>>n>>s; 48 for (i=1;i<=n;i++) 49 scanf("%d",&val[i]); 50 for (i=1;i<=n-1;i++) 51 { 52 scanf("%d%d",&u,&v); 53 add(u,v); 54 fa[v]=u; 55 } 56 dfs(1); 57 cout<<ans; 58 }

[JLOI2012]樹