这道题可以说是[HNOI2003]消防局的设立的升级版。距离从2改为了d。
辛亏d只有20,这也就是一个切入点。
令f[u][j]表示u四周 j - 1的距离需要被覆盖,g[u][j]表示u可以像四周覆盖 j 的距离。
考虑转移方程,令v为u的其中一个儿子:
1.f[u][j]:直接从v延伸而来:f[u][j] = Σ f[v][j - 1]。
2.g[u][j]:用前几个儿子已经得出的g[u][j]去覆盖v:g[u][j] = g[u][j] + f[v][j];或者用v覆盖u:g[now][j] = f[now][j +1] +g[v][j + 1],所以g[now][j] = min{g[now][j] + f[v][j], f[now][j + 1] + g[v][j + 1]}.
对于f,可能距离小的比大的还优,所以还要再求一遍前缀最小值:f[now][j] = min{f[now][k]} (0 <= k < j)
同理对于g,可能覆盖距离大的比距离小的还优,所以后缀最小值:g[now][j] = min{g[now][k]} (j < k <= d)
最后考虑的是初值:显然g[now][j] = c[now] (1 <= j <= d)。然后如果这个点B神可能出现,f[now][0] = g[now][0] = c[now],表示这个点需要覆盖。
(代码折叠坏啦)
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<algorithm> 5 #include<cstring> 6 #include<cstdlib> 7 #include<cctype> 8 #include<vector> 9 #include<stack> 10 #include<queue> 11 using namespace std; 12 #define enter puts("") 13 #define space putchar(' ') 14 #define Mem(a, x) memset(a, x, sizeof(a)) 15 #define rg register 16 typedef long long ll; 17 typedef double db; 18 const int INF = 0x3f3f3f3f; 19 const db eps = 1e-8; 20 const int maxn = 5e5 + 5; 21 inline ll read() 22 { 23 ll ans = 0; 24 char ch = getchar(), last = ' '; 25 while(!isdigit(ch)) {last = ch; ch = getchar();} 26 while(isdigit(ch)) {ans = (ans << 1) + (ans << 3) + ch - '0'; ch = getchar();} 27 if(last == '-') ans = -ans; 28 return ans; 29 } 30 inline void write(ll x) 31 { 32 if(x < 0) x = -x, putchar('-'); 33 if(x >= 10) write(x / 10); 34 putchar(x % 10 + '0'); 35 } 36 37 int n, d, m, c[maxn]; 38 bool vis[maxn]; 39 40 struct Edge 41 { 42 int nxt, to; 43 }e[maxn << 1]; 44 int head[maxn], ecnt = -1; 45 void addEdge(int x, int y) 46 { 47 e[++ecnt] = (Edge){head[x], y}; 48 head[x] = ecnt; 49 } 50 51 int f[maxn][22], g[maxn][22]; 52 void dfs(int now, int _f) 53 { 54 for(int i = 1; i <= d; ++i) g[now][i] = c[now]; 55 if(vis[now]) f[now][0] = g[now][0] = c[now]; 56 g[now][d + 1] = INF; 57 for(int i = head[now], v; i != -1; i = e[i].nxt) 58 { 59 v = e[i].to; 60 if(v == _f) continue; 61 dfs(v, now); 62 for(int j = d; j >= 0; --j) g[now][j] = min(g[now][j] + f[v][j], f[now][j + 1] + g[v][j + 1]); 63 for(int j = d; j >= 0; --j) g[now][j] = min(g[now][j], g[now][j + 1]); 64 f[now][0] = g[now][0]; 65 for(int j = 1; j <= d; ++j) f[now][j] += f[v][j - 1]; 66 for(int j = 1; j <= d; ++j) f[now][j] = min(f[now][j], f[now][j - 1]); 67 } 68 } 69 70 int main() 71 { 72 Mem(head, -1); 73 n = read(); d = read(); 74 for(int i = 1; i <= n; ++i) c[i] = read(); 75 m = read(); 76 for(int i = 1; i <= m; ++i) {int x = read(); vis[x] = 1;} 77 for(int i = 1; i < n; ++i) 78 { 79 int x = read(), y = read(); 80 addEdge(x, y); addEdge(y, x); 81 } 82 dfs(1, 0); 83 write(f[1][0]), enter; 84 return 0; 85 }