JLOI/SHOI2016侦查守卫

树形DP,较复杂


SOL:

\(f[i][j]i\)点向上\(j\)层都可以被监视最小代价(当前点为第0层)

\(g[i][j]i\)点向下\(j\)层都无法别监视最小代价(当前点为第1层)

初始值:

需守卫的点:\(f[x][0]=g[x][0]=w[x]\)

其余点:\(f[x][0]=g[x][0]=0\)

所有点:\(f[x][i]=w[x](i>0)\)

转移方程:

\[f[x][i]=min(f[x][i]+min(g[v][i],f[v][i+1]),g[x][i+1]+f[v][i+1]) \]

\[f[x][i]=min(f[x][i],f[x][i+1]) \]

\[g[x][0]=f[x][0] \]

\[g[x][i]+=g[v][i-1] \]

\[g[x][i]=min(g[x][i],g[x][i-1]) \]

#include<bits/stdc++.h>
using namespace std;
inline int read(){
	int x=0,f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	return f==1?x:-x;
}
const int N=5e5+4,D=24;
int n,m,d,a[N],f[N][D],g[N][D],w[N];
vector<int>e[N];
void dfs(int x,int fa){
	if(a[x])f[x][0]=g[x][0]=w[x];
	else f[x][0]=g[x][0]=0;
	for(int i=1;i<=d;i++)f[x][i]=w[x];
	for(auto v:e[x]){
		if(v==fa)continue;
		dfs(v,x);
		for(int i=d;i>=0;i--){
			f[x][i]=min(min(f[x][i]+g[v][i],g[x][i+1]+f[v][i+1]),f[x][i]+f[v][i+1]);
			f[x][i]=min(f[x][i+1],f[x][i]);
		}
		g[x][0]=f[x][0];
		for(int i=1;i<=d+1;i++){
			g[x][i]=g[x][i]+g[v][i-1];
			g[x][i]=min(g[x][i],g[x][i-1]);
		}
	}
}
int main(){
	n=read();d=read();
	for(int i=1;i<=n;i++)w[i]=read();
	m=read();
	for(int i=1;i<=m;i++)a[read()]=1;
	for(int i=1,u,v;i<n;i++){
		u=read();v=read();
		e[u].push_back(v);e[v].push_back(u);
	}
	memset(f,0x3f,sizeof(f));
	dfs(1,0);
	cout<<f[1][0];
	return (0-0);
}
posted @ 2020-03-20 23:16  starusc  阅读(169)  评论(0)    收藏  举报