P3267 [JLOI2016/SHOI2016]偵察守衛
阿新 • • 發佈:2019-03-24
long long col 接下來 連通 答案 code 地圖 return truct \(\color{#0066ff}{輸入格式}\)
\(\color{#0066ff}{輸入樣例}\)
所以我們再開一個\(g[i][j]\)
$ \color{#0066ff}{ 題目描述 }$
小R和B神正在玩一款遊戲。這款遊戲的地圖由N個點和N-1條無向邊組成,每條無向邊連接兩個點,且地圖是連通的。換句話說,遊戲的地圖是一棵有N個節點的樹。
遊戲中有一種道具叫做偵查守衛,當一名玩家在一個點上放置偵查守衛後,它可以監視這個點以及與這個點的距離在D以內的所有點。這裏兩個點之間的距離定義為它們在樹上的距離,也就是兩個點之間唯一的簡單路徑上所經過邊的條數。在一個點上放置偵查守衛需要付出一定的代價,在不同點放置守衛的代價可能不同。
現在小R知道了所有B神可能會出現的位置,請你計算監視所有這些位置的最小代價。
\(\color{#0066ff}{輸入格式}\)
第一行包含兩個正整數N和D,分別表示地圖上的點數和偵查守衛的視野範圍。約定地圖上的點用1到N的整數編號。
第二行N個正整數,第i個正整數表示在編號為i的點放置偵查守衛的代價Wi。保證Wi<=1000。
第三行一個正整數M,表示B神可能出現的點的數量。保證M<=N。
第四行M個正整數,分別表示每個B神可能出現的點的編號,從小到大不重復地給出。
接下來N-1行,每行包含兩個正整數U,V,表示在編號為U的點和編號為V的點之間有一條無向邊。
\(\color{#0066ff}{輸出格式}\)
僅一行一個整數,表示監視所有B神可能出現的點所需要的最小代價
\(\color{#0066ff}{輸入樣例}\)
12 2
8 9 12 6 1 1 5 1 4 8 10 6
10
1 2 3 5 6 7 8 9 10 11
1 3
2 3
3 4
4 5
4 6
4 7
7 8
8 9
9 10
10 11
11 12
\(\color{#0066ff}{輸出樣例}\)
10
\(\color{#0066ff}{數據範圍與提示}\)
對於所有的數據,N<=500000,D<=20
\(\color{#0066ff}{題解}\)
對於這種在樹上覆蓋的問題,是一個比較經典的樹形DP模型
狀態\(f[i][j]\)表示以i為根子樹從i向下有j層未覆蓋的最小代價,j可以為負數,如果是負數,就是子樹全覆蓋,並向外覆蓋一些層
所以我們再開一個\(g[i][j]\) 表示以i為根子樹全覆蓋,並且向外覆蓋了j層的方案數
首先,對於必覆蓋點,初始化就是\(f[i][0]=g[i][0]=val[i]\)
註意當\(j\ge 1\)時,f覆蓋的範圍是不包括當前點的(j層未覆蓋),但是g包括了(i向外j全覆蓋)
所以\(g[i][j]\)也要初始化一下
考慮轉移
對於f,顯然有\(f[x][j] = min\{f[x][j-1]\}\)
還有就是子樹統計\(f[x][j]+=f[y][j-1]\)
對於g,顯然有\(g[x][i]=min\{g[x][i+1]\}\)
還有,就是考慮x的外面由哪個子樹覆蓋,這個覆蓋包括了x子樹內部,\(g[y][j]\)覆蓋了\(f[x][j]\)未覆蓋的j層
\(g[x][j]=min\{f[x][j+1]+g[y][j+1],f[y][j]+g[x][j]\}\)
答案就是\(f[1][0]\)
#include<bits/stdc++.h>
#define LL long long
LL in() {
char ch; LL x = 0, f = 1;
while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
return x * f;
}
const int maxn = 5e5 + 100;
const int inf = 0x7fffffff;
int f[maxn][25], g[maxn][25], val[maxn];
int n, d, m;
bool vis[maxn];
struct node {
int to;
node *nxt;
node(int to = 0, node *nxt = NULL): to(to), nxt(nxt) {}
};
node *head[maxn];
void add(int from, int to) { head[from] = new node(to, head[from]); }
void dfs(int x, int fa) {
if(vis[x]) f[x][0] = g[x][0] = val[x];
for(int i = 1; i <= d; i++) g[x][i] = val[x];
g[x][d + 1] = inf;
for(node *i = head[x]; i; i = i->nxt) {
if(i->to == fa) continue;
dfs(i->to, x);
for(int j = 0; j <= d; j++) g[x][j] = std::min(g[x][j] + f[i->to][j], g[i->to][j + 1] + f[x][j + 1]);
for(int j = d - 1; j >= 0; j--) g[x][j] = std::min(g[x][j], g[x][j + 1]);
f[x][0] = g[x][0];
for(int j = 1; j <= d; j++) f[x][j] += f[i->to][j - 1];
for(int j = 1; j <= d; j++) f[x][j] = std::min(f[x][j], f[x][j - 1]);
}
}
int main() {
n = in(), d = in();
for(int i = 1; i <= n; i++) val[i] = in();
m = in();
for(int i = 1; i <= m; i++) vis[in()] = true;
int x, y;
for(int i = 1; i < n; i++) x = in(), y = in(), add(x, y), add(y, x);
dfs(1, 0);
printf("%d\n", f[1][0]);
return 0;
}
P3267 [JLOI2016/SHOI2016]偵察守衛