首页 > 代码库 > [luoguP3252] [JLOI2012]树(DP)

[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

 

[luoguP3252] [JLOI2012]树(DP)