JLOI2016 侦查守卫

侦查守卫

小R和B神正在玩一款游戏。这款游戏的地图由 N 个点和 N-1 条无向边组成,每条无向边连接两个点,且地图是连通的。换句话说,游戏的地图是一棵有 N 个节点的树。

游戏中有一种道具叫做侦查守卫,当一名玩家在一个点上放置侦查守卫后,它可以监视这个点以及与这个点的距离在 D 以内的所有点。这里两个点之间的距离定义为它们在树上的距离,也就是两个点之间唯一的简单路径上所经过边的条数。在一个点上放置侦查守卫需要付出一定的代价,在不同点放置守卫的代价可能不同。

现在小R知道了所有B神可能会出现的位置,请你计算监视所有这些位置的最小代价。

对于所有的数据,N<=500000,D<=20

题解

  • 状态设计

假设当前到了 x 的子树,现在该合并 x 的第 k 个子树。

f[x][j] 表示 x 的前 k-1 个子树该覆盖的完全覆盖,而且还能向四周覆盖 j 层(不含 x )的最小代价。

对于第 k 个子树的意义就是,兄弟子树放置的守卫可以帮 x 的第 k 个子树覆盖前 j 层(第 1 层为 x 的子节点),那么相应的就要有一个状态来表示这个 可以让兄弟子树帮忙覆盖 的前 j 层。

g[x][j] 表示还需要覆盖 x 的前 k 个子树中的前 j 层(含 x),且第 j 层以下该覆盖的完全覆盖的最小代价。

  • 状态转移

要能向 x 的四周覆盖 j 层,只需要 x 的子节点中有一个子节点 z 能向上覆盖 j+1 层即可。所以

f[x][j] = min(f[x][j]+g[y][j] ,f[y][j+1]+g[x][j+1])

g[x][j] += g[y][j-1]

但是有可能更新后 x 能向上恰好覆盖 j 层的代价要小于能向上恰好覆盖 j-1 层的代价;也有可能 x 需要向下覆盖 j 层的代价小于再向下覆盖 j+1 层的代价。

所以将f的状态定义改为 向上覆盖至少j层的最小代价

同理,g的状态定义改为还需要覆盖至多j层的最小代价

所以要对f[x]做一个后缀最小值,g[x]做一个前缀最小值。

时间复杂度\(O(ND)\)

#include<bits/stdc++.h>
#define co const
#define il inline
template<class T> T read(){
	T x=0,w=1;char c=getchar();
	for(;!isdigit(c);c=getchar())if(c=='-') w=-w;
	for(;isdigit(c);c=getchar()) x=x*10+c-'0';
	return x*w;
}
template<class T> il T read(T&x){
	return x=read<T>();
}
using namespace std;
typedef long long LL;

co int N=500000+10,D=21;
int n,dis,w[N],use[N];
vector<int> to[N];
int f[N][D],g[N][D];

void dfs(int x,int fa){
	for(int i=1;i<=dis;++i) f[x][i]=w[x];
	if(use[x]) g[x][0]=f[x][0]=w[x];
	f[x][dis+1]=1e9;
	for(int i=0;i<(int)to[x].size();++i){
		int y=to[x][i];
		if(y==fa) continue;
		dfs(y,x);
		for(int j=0;j<=dis;++j)	
			f[x][j]=min(f[x][j]+g[y][j],f[y][j+1]+g[x][j+1]);
		for(int j=dis;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<=dis;++j)
			g[x][j]+=g[y][j-1];
		for(int j=1;j<=dis;++j)
			g[x][j]=min(g[x][j],g[x][j-1]);
	}
}
int main(){
	read(n),read(dis);
	for(int i=1;i<=n;++i) read(w[i]);
	for(int m=read<int>();m--;) use[read<int>()]=1;
	for(int i=1;i<n;++i){
		int x=read<int>(),y=read<int>();
		to[x].push_back(y),to[y].push_back(x);
	}
	dfs(1,0);
	printf("%d\n",g[1][0]);
	return 0;
}

posted on 2019-08-17 20:21  autoint  阅读(235)  评论(0)    收藏  举报

导航