BZOJ 2783 [JLOI2012]树 【树上倍增】 BZOJ 2783  [JLOI2012]树

Descriptions:

在这个问题中,给定一个值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。

题解:

枚举每一个节点,然后暴力往上搜会爆。所以这里就要用到树上倍增。

总复杂度 nlogn 。

贴代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N=100005;
 4 int n,s;
 5 int a[N];
 6 struct node{
 7     int x,y,nxt;
 8 }e[N];
 9 int num,hea[N];
10 void add(int x,int y)
11 {
12     e[++num].x=x,e[num].y=y,e[num].nxt=hea[x];
13     hea[x]=num;
14 }
15 int f[N][21];
16 int dep[N];
17 void dfs(int x)
18 {
19     for (int i=1; i<=21; i++)
20       if (f[x][i-1]!=0)  
21         f[x][i]=f[f[x][i-1]][i-1];
22     for (int i=hea[x]; i!=-1; i=e[i].nxt)
23     {
24         int u=e[i].y;
25         dep[u]=dep[x]+a[u];
26         f[u][0]=x;
27         dfs(u);
28     }
29 }
30 int ans=0;
31 void solve(int x)
32 {
33     int y=x;
34     for (int i=20; i>=0; i--)
35       if (dep[x]-dep[f[y][i]]<=s)
36         y=f[y][i];
37       if (dep[x]-dep[y]==s) ans++;
38       for (int i=hea[x]; i!=-1; i=e[i].nxt)
39         solve(e[i].y);
40 }
41 int main()
42 {
43     num=0; memset(hea,-1,sizeof(hea));
44     scanf("%d%d",&n,&s);
45     for (int i=1; i<=n; i++) scanf("%d",&a[i]);
46     for (int i=1; i<n; i++)
47     {
48         int x,y;
49         scanf("%d%d",&x,&y);
50         add(x,y);
51     }
52     dep[1]=a[1]; f[1][0]=0; dfs(1);
53     solve(1);
54     printf("%d
",ans);
55     return 0;
56 }
View Code

加油加油加油!!!fighting fighting fighting!!!