[luoguP3252] [JLOI2012]树(DP)

传送门

 

树上前缀和。

在树上找一条权值和为 s 的链,其中这个链上的点按深度递增(递减)(不同)

dfs

每搜到一个点求它的前缀和 sum[x],放入 set 中。

在 set 中找 sum[x] - s 的点,如果有,ans++

退出 dfs 的时候再把 sum[x] 从 set 中删除

因为每个点权都是正整数,所以 set 中没有重复元素。

同时也是单调递增,所以简单些不用 set,开个数组再 lower_bound 也行。

 

——代码

 1 #include <set>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <iostream>
 5 
 6 const int MAXN = 100001;
 7 int n, s, cnt, ans;
 8 int a[MAXN], head[MAXN], to[MAXN << 1], next[MAXN << 1], f[MAXN], sum[MAXN];
 9 std::set <int> S;
10 
11 inline int read()
12 {
13     int x = 0, f = 1;
14     char ch = getchar();
15     for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1;
16     for(; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + ch - '0';
17     return x * f;
18 }
19 
20 inline void add(int x, int y)
21 {
22     to[cnt] = y;
23     next[cnt] = head[x];
24     head[x] = cnt++;
25 }
26 
27 inline void dfs(int u)
28 {
29     sum[u] = sum[f[u]] + a[u];
30     S.insert(sum[u]);
31     if(S.count(sum[u] - s)) ans++;
32     for(int i = head[u]; i ^ -1; i = next[i]) dfs(to[i]);    
33     S.erase(sum[u]);
34 }
35 
36 int main()
37 {
38     int i, x, y;
39     n = read();
40     s = read();
41     memset(head, -1, sizeof(head));
42     for(i = 1; i <= n; i++) a[i] = read();
43     for(i = 1; i < n; i++)
44     {
45         x = read();
46         y = read();
47         f[y] = x;
48         add(x, y);
49     }
50     S.insert(0);
51     dfs(1);
52     printf("%d\n", ans);
53     return 0;
54 }
View Code

 

posted @ 2017-05-26 20:54  zht467  阅读(115)  评论(0编辑  收藏  举报