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
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\n",ans); 55 return 0; 56 }
加油加油加油!!!fighting fighting fighting!!!