bzoj4557【JLOI2016】侦查守卫
这道题对于我来说并不是特别简单,还可以。
更新一下blog
树形DP
f[i][j]表示i的子树中,最高覆盖到i向下第j层的最小花费。
g[i][j]表示i的子树全部覆盖,还能向上覆盖j层的最小花费。
这样还是有许多细节的。
1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #include<iostream> 5 #include<cmath> 6 #include<cstring> 7 using namespace std; 8 9 const int NN=500007,INF=1e9+7,DD=22; 10 11 int n,m,d; 12 int w[NN],g[NN][DD]={0},f[NN][DD]={0}; 13 int cnt,head[NN],next[NN*2],rea[NN*2]; 14 bool mark[NN]; 15 16 void add(int u,int v) 17 { 18 cnt++; 19 next[cnt]=head[u]; 20 head[u]=cnt; 21 rea[cnt]=v; 22 } 23 void dfs(int u,int fa) 24 { 25 if (mark[u]) f[u][0]=g[u][0]=w[u]; 26 for (int i=1;i<=d;i++) 27 g[u][i]=w[u]; 28 g[u][d+1]=INF; 29 for (int i=head[u];i!=-1;i=next[i]) 30 { 31 int v=rea[i]; 32 if (v==fa) continue; 33 dfs(v,u); 34 for (int j=d;j>=0;j--) 35 g[u][j]=min(f[v][j]+g[u][j],f[u][j+1]+g[v][j+1]); 36 for (int j=d;j>=0;j--) 37 g[u][j]=min(g[u][j],g[u][j+1]); 38 f[u][0]=g[u][0]; 39 for (int j=1;j<=d;j++) 40 f[u][j]+=f[v][j-1]; 41 for (int j=1;j<=d;j++) 42 f[u][j]=min(f[u][j-1],f[u][j]); 43 } 44 } 45 int main() 46 { 47 int x,y,z; 48 memset(head,-1,sizeof(head)); 49 scanf("%d%d",&n,&d); 50 for (int i=1;i<=n;i++) 51 scanf("%d",&w[i]); 52 scanf("%d",&m); 53 for (int i=1;i<=m;i++) 54 { 55 scanf("%d",&x); 56 mark[x]=true; 57 } 58 for (int i=1;i<n;i++) 59 { 60 scanf("%d%d",&x,&y); 61 add(x,y),add(y,x); 62 } 63 dfs(1,0); 64 printf("%d",f[1][0]); 65 }