BZOJ 4557: [JLoi2016]侦察守卫

题目大意:
每个点有一个放置守卫的代价,同时每个点放置守卫能覆盖到的距离都为d,问覆盖所有给定点的代价是多少。

题解:

树形DP

f[x][y]表示x子树中所有点都已经覆盖完,并且x还能向上覆盖y层的最小代价。
g[x][y]表示x的y层及以下的所有点都已经覆盖完,还需要覆盖上面的y层的最小代价。

代码:

#include<cstdio>
#include<algorithm>
using namespace std;
int n,d,cnt,m,last[1000005],f[1000005][21],g[1000005][21],vis[1000005],w[1000005];
struct node{
	int to,next;
}e[1000005];
void add(int a,int b){
	e[++cnt].to=b;
	e[cnt].next=last[a];
	last[a]=cnt;
}
void dfs(int x,int fa){
	if (vis[x]) f[x][0]=g[x][0]=w[x];
	for (int i=1; i<=d; i++) f[x][i]=w[x];
	f[x][d+1]=1e9;
	for (int i=last[x]; i; i=e[i].next){
		int V=e[i].to;
		if (V==fa) continue;
		dfs(V,x);
		for (int j=d; j>=0; j--)
			f[x][j]=min(f[x][j]+g[V][j],g[x][j+1]+f[V][j+1]);
		for (int j=d; j>=0; j--)
			f[x][j]=min(f[x][j],f[x][j+1]);
		g[x][0]=f[x][0];
		for (int j=1; j<=d; j++)
			g[x][j]+=g[V][j-1];
		for (int j=1; j<=d; j++)
			g[x][j]=min(g[x][j],g[x][j-1]);
	}
}
int main(){
	scanf("%d%d",&n,&d);
	for (int i=1; i<=n; i++)
		scanf("%d",&w[i]);
	scanf("%d",&m);
	for (int i=1; i<=m; i++){
		int x;
		scanf("%d",&x);
		vis[x]=1;
	}
	for (int i=1; i<n; i++){
		int x,y;
		scanf("%d%d",&x,&y);
		add(x,y);
		add(y,x);
	}
	dfs(1,0);
	printf("%d\n",f[1][0]);
	return 0;
}

  

 

posted @ 2018-07-22 20:38  ~Silent  阅读(155)  评论(0编辑  收藏  举报
Live2D