树上前缀和。
在树上找一条权值和为 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 }
时间: 2024-12-11 16:56:14