今天开始尽量补一补欠的70多道题的blog...(菜啊)
都是几句话的事 周末大概就完了
一看不是树dp经典题吗 最小覆盖
然后告诉我有些点不必覆盖?
20minutes later 发现其实是一样的...因为不必覆盖不是一定不能覆盖
其实是我一开始想成记录放的节点个数那个题 然后状态设计跪了
还是说一下数组吧:
f[i][j]表示从i点向下 已知 的子树最多延伸j步没有覆盖的最小花费
g[i][j]表示从i点向上 已知 的子树最多能延伸j步覆盖其他点的最小花费
自然遍历儿子的时候先递归 回溯的时候更新
先是g[x][i]
逆序更新
我们要加上现在这个子树所有的点 两种情况:
g[x][i] = g[x][i] + f[sn][i] 利用其他子树覆盖 最多覆盖j的距离所以j以下由后面那个f[][]覆盖
g[x][i] = g[sn][i+1] + f[x][i+1] 利用这个子树覆盖 可以覆盖其他子树i-1的距离 i及一下由后面那个f[][]覆盖
然后取最小值
(自己画个图就OK)
然后更新f[x][i]
顺序更新
首先f[x][0] = g[x][0](意义相同)
然后f[x][i] = ∑(v∈sn)f[sn][i-1] 同上 i-1步以下要覆盖好
同时g[x][i] = min(g[x][i],g[x][i+1]) f[x][i] = min(f[x][i],f[x][i-1]) (可以看做是后面两项的退化)
然后就是初始化 如果要求覆盖该点那么f[x][0] = g[x][0] = w[x]
同时更新之前先判断x放点 也就是g[x][i] = w[x]
(没想到小细节一说出来挺多的...)
注意g[x][d+1] = inf....
不要设f[]g[]初值是inf....inf不要太大.....
Time cost: 55min
Code:
1 #include<cstdio>
2 #include<cstring>
3 #include<algorithm>
4 #include<queue>
5 #include<iostream>
6 #include<cmath>
7 #define ms(a,b) memset(a,b,sizeof a)
8 #define rep(i,a,n) for(int i = a;i <= n;i++)
9 #define per(i,n,a) for(int i = n;i >= a;i--)
10 #define inf 1e9+7
11 using namespace std;
12 typedef long long ll;
13 typedef double D;
14 #define eps 1e-8
15 ll read() {
16 ll as = 0,fu = 1;
17 char c = getchar();
18 while(c < '0' || c > '9') {
19 if(c == '-') fu = -1;
20 c = getchar();
21 }
22 while(c >= '0' && c <= '9') {
23 as = as * 10 + c - '0';
24 c = getchar();
25 }
26 return as * fu;
27 }
28 //head
29 const int N = 500005;
30 int n,d;
31 int head[N],nxt[N<<1],mo[N<<1],cnt;
32 void _add(int x,int y) {
33 mo[++cnt] = y;
34 nxt[cnt] = head[x];
35 head[x] = cnt;
36 }
37 void add(int x,int y) {if(x^y)_add(x,y),_add(y,x);}
38 bool vis[N];
39 int w[N],f[N][21],g[N][21];
40
41 void dfs(int x,int p) {
42 if(vis[x]) f[x][0] = g[x][0] = w[x];
43 rep(i,1,d) g[x][i] = w[x];
44 g[x][d+1] = (int)inf;
45 for(int i = head[x];i;i = nxt[i]) {
46 int sn = mo[i];
47 if(sn == p) continue;
48 dfs(sn,x);
49 per(i,d,0) g[x][i] = min(g[x][i] + f[sn][i],f[x][i+1] + g[sn][i+1]);
50 per(i,d,0) g[x][i] = min(g[x][i],g[x][i+1]);
51 f[x][0] = g[x][0];
52 rep(i,1,d+1) f[x][i] += f[sn][i-1];
53 rep(i,1,d+1) f[x][i] = min(f[x][i],f[x][i-1]);
54 }
55 }
56
57 int main() {
58 n = read(),d = read();
59 rep(i,1,n) w[i] = read();
60 int m = read();
61 rep(i,1,m) vis[read()] = 1;
62 rep(i,2,n) add(read(),read());
63 dfs(1,1);
64 printf("%d
",f[1][0]);
65 return 0;
66 }