[JLOI2016/SHOI2016]侦察守卫

嘟嘟嘟

这道题可以说是[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 }

猜你喜欢

转载自www.cnblogs.com/mrclr/p/9907146.html