思路
树形 DP。
设 sum[u] 表示以 u 为根的子树权值和。
如果 sum[u] == target,则可以断开 u 与父节点的边,形成一个合法连通块。
但 target 可能为 0,且 val 可能为负,因此不能简单贪心。
需要 DFS 后序处理,统计每个子树能否独立成块。
设 dp[u] 表示以 u 为根的子树中,能形成的合法连通块数量。
若 sum[u] == target,则 dp[u]++,并将 sum[u] 置为 0,表示这个块已经独立。
最后如果整棵树的 sum[root] == target 或 sum[root] == 0 且 root 已被处理,则答案有效。
代码
c
#include <stdio.h>
#include <stdlib.h>
#define MAXN 200005
typedef struct Edge {
int to, next;
} Edge;
Edge edges[MAXN * 2];
int head[MAXN], edgeCnt = 0;
int val[MAXN];
long long sum[MAXN];
int dp[MAXN];
int target;
int ans = 0;
void addEdge(int u, int v) {
edges[++edgeCnt] = (Edge){v, head[u]};
head[u] = edgeCnt;
}
void dfs(int u, int parent) {
sum[u] = val[u];
for (int e = head[u]; e; e = edges[e].next) {
int v = edges[e].to;
if (v == parent) continue;
dfs(v, u);
sum[u] += sum[v];
dp[u] += dp[v];
}
if (sum[u] == target) {
dp[u]++;
sum[u] = 0;
}
}
int main() {
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i++) scanf("%d", &val[i]);
scanf("%d", &target);
for (int i = 1; i < n; i++) {
int u, v;
scanf("%d %d", &u, &v);
addEdge(u, v);
addEdge(v, u);
}
dfs(1, 0);
if (sum[1] == 0 && dp[1] > 0)
printf("%d\n", dp[1] - 1);
else
printf("-1\n");
return 0;
}