luoguP3267 [JLOI2016/SHOI2016] 偵查守衛 樹dp
今天開始儘量補一補欠的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\n",f[1][0]);
65 return 0;
66 }
View Code