[bzoj4557]侦察守卫
令g[i][j]表示覆盖了i的子树中距离i大于等于j的所有点,f[i][j]表示覆盖了i的子树和子树外距离i小于等于j的所有点,有递推式$f[i][j]=min(f[i][j]+g[son][j],f[son][j+1]+g[i][j+1]),g[i][j]+=g[son][j-1]$,特别的有g[i][0]=f[i][0]
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 500005 4 struct ji{ 5 int nex,to; 6 }edge[N<<1]; 7 int E,n,d,x,y,w[N],vis[N],head[N],f[N][31],g[N][31]; 8 void add(int x,int y){ 9 edge[E].nex=head[x]; 10 edge[E].to=y; 11 head[x]=E++; 12 } 13 void dfs(int k,int fa){ 14 if (vis[k])f[k][0]=g[k][0]=w[k]; 15 for(int i=1;i<=d;i++)f[k][i]=w[k]; 16 f[k][d+1]=0x3f3f3f3f; 17 for(int i=head[k];i!=-1;i=edge[i].nex) 18 if (edge[i].to!=fa){ 19 int v=edge[i].to; 20 dfs(v,k); 21 for(int j=0;j<=d;j++)f[k][j]=min(f[k][j]+g[v][j],f[v][j+1]+g[k][j+1]); 22 for(int j=d;j>=0;j--)f[k][j]=min(f[k][j],f[k][j+1]); 23 g[k][0]=f[k][0]; 24 for(int j=1;j<=d;j++)g[k][j]+=g[v][j-1]; 25 for(int j=1;j<=d;j++)g[k][j]=min(g[k][j],g[k][j-1]); 26 } 27 } 28 int main(){ 29 scanf("%d%d",&n,&d); 30 for(int i=1;i<=n;i++)scanf("%d",&w[i]); 31 scanf("%d",&x); 32 for(int i=1;i<=x;i++){ 33 scanf("%d",&y); 34 vis[y]=1; 35 } 36 memset(head,-1,sizeof(head)); 37 for(int i=1;i<n;i++){ 38 scanf("%d%d",&x,&y); 39 add(x,y); 40 add(y,x); 41 } 42 dfs(1,0); 43 printf("%d",f[1][0]); 44 }