1. 程式人生 > >[JLOI2016/SHOI2016]偵察守衛

[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 }