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 }

 

posted @ 2017-08-16 21:32  Kaiser-  阅读(220)  评论(0编辑  收藏  举报