Description:
一棵树中有些黑点,在每个点上放守卫要花一定代价,守卫侦查范围为d,求覆盖所有黑点最小代价。
Solution:
这是一类树形
dp
d
p
。
设
up[u][i]
u
p
[
u
]
[
i
]
为
u
u
向上至少覆盖,
down[u][i]
d
o
w
n
[
u
]
[
i
]
为
u
u
最多只有向下层没覆盖。然后转移看代码。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 5e5 + 5;
struct edge {
int nxt, to;
} e[N << 1];
int n, cnt = 1, D, m;
int w[N], mark[N], down[N][21], up[N][21], h[N];
void link(int u, int v) {
e[++cnt].nxt = h[u];
h[u] = cnt;
e[cnt].to = v;
}
void dfs(int u, int last) {
if(mark[u]) {
down[u][0] = up[u][0] = w[u];
}
for(int i = 1; i <= D; ++i) {
up[u][i] = w[u];
}
up[u][D + 1] = 0x3f3f3f3f;
for(int i = h[u]; i; i = e[i].nxt) {
if(e[i].to != last) {
dfs(e[i].to, u);
int v = e[i].to;
for(int j = D; ~j; --j) {
up[u][j] = min(up[u][j] + down[v][j], down[u][j + 1] + up[v][j + 1]);
up[u][j] = min(up[u][j], up[u][j + 1]);
}
down[u][0] = up[u][0];
for(int j = 1; j <= D + 1; ++j) {
down[u][j] += down[v][j - 1];
}
for(int j = 0; j <= D; ++j) {
down[u][j + 1] = min(down[u][j + 1], down[u][j]);
}
}
}
}
int main() {
scanf("%d%d", &n, &D);
for(int i = 1; i <= n; ++i) {
scanf("%d", &w[i]);
}
scanf("%d", &m);
for(int i = 1; i <= m; ++i) {
int x;
scanf("%d", &x);
mark[x] = 1;
}
for(int i = 1; i < n; ++i) {
int u, v;
scanf("%d%d", &u, &v);
link(u, v);
link(v, u);
}
dfs(1, 0);
printf("%d\n", down[1][0]);
return 0;
}