「JLOI / SHOI2016」侦查守卫

树上的动态规划

对于一棵子树内的守卫,也可以覆盖子树外的节点,需要加一维来记录子树与外界的关系。

g[u][j] 表示覆盖完子树并且还可以覆盖离子树根节点距离不大于j的点的最小花费

f[u][j] 表示子树内只保证距离子树根节点距离不小于j的节点被覆盖的最小花费

讨论树的子树对于树的关系来转移:

u是v的父亲,则

g[u][j]=min(g[u][j]+f[v][j],g[v][j+1]+f[u][j+1])

f[u][j] = Σf[v][j-1]

g[u][j] = min(g[u][j], g[u][j+1])

f[u][j] = min(f[u][j], f[u][j-1]) 

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int N = 5e5 + 5, M = 25;
 5 
 6 int n, d, cnt, first[N], w[N], f[N][M], g[N][M], m, inf = 1e9;
 7 bool vis[N];
 8 struct Edge {
 9     int to, next;
10 } e[N<<1];
11 
12 void dfs(int u, int fa) {
13     if(vis[u]) f[u][0] = g[u][0] = w[u];
14     for(int i = 1; i <= d; i++) g[u][i] = w[u];
15     g[u][d + 1] = inf;
16     for(int i = first[u]; i != -1; i = e[i].next) {
17         int v = e[i].to;
18         if(v == fa) continue;
19         dfs(v, u);
20         for(int j = 0; j <= d; j++)
21            g[u][j] = min(g[u][j] + f[v][j], g[v][j + 1] + f[u][j + 1]);
22         for(int j = d; j >= 0; j--) g[u][j] = min(g[u][j], g[u][j + 1]);
23         f[u][0] = g[u][0];
24         for(int j = 1; j <= d; j++)
25            f[u][j] += f[v][j - 1];
26         for(int j = 1; j <= d; j++)
27            f[u][j] = min(f[u][j], f[u][j - 1]);
28     }
29 }
30 
31 void add(int u, int v) {
32     e[cnt] = (Edge) {v, first[u]};
33     first[u] = cnt++;
34 }
35 
36 int Read() {
37     int f = 1, res = 0;
38     char ch = getchar();
39     while(ch > '9' || ch < '0') {
40         if(ch == '-') f =- 1;
41         ch = getchar();
42     }
43     while(ch >= '0' && ch <= '9') {
44         res = res*10 + ch - '0';
45         ch = getchar();
46     }
47     return res*f;
48 }
49 
50 int main() {
51     n = Read(); d = Read();
52     memset(first, -1, sizeof(first));
53     for(int i = 1; i <= n; i++)
54        w[i] = Read();
55     m = Read();
56     for(int i = 1; i <= m; i++)
57        vis[Read()] = 1;
58     for(int i = 1, u, v; i < n; i++) {
59         u = Read(); v = Read();
60         add(u, v); add(v, u);
61     } 
62     dfs(1, 0);
63     printf("%d\n", f[1][0]);
64     return 0;
65 } 

猜你喜欢

转载自www.cnblogs.com/ympc2005/p/12307186.html