题解 P3267 【[JLOI2016]侦察守卫】

zcysky

2017-04-29 17:59:25

Solution

首先我认为**楼上的动态规划方程是错的**,状态不倒序存的话难道数量不会爆炸? 题意:每个点有一个覆盖半径,求覆盖完整棵树的最小代价。 定义状态: $f[i][j]$ 表示在子树$i$ 中,向下还有深度$j$ 没有被覆盖的最小代价。 $g[i][j]$子树$i $已经被完全覆盖,向上已经覆盖了$j $层所需要的最小代价。 那么如果我们到了第$x $个节点,开始枚举第$u $个子树,我们需要的方程是: $f[x][j]=min(min(f[x][j]+g[u][j],g[x][j+1]+f[u][j+1]),f[x][j-1])$ $g[x][0]=f[x][0]$ $g[x][i]=min(g[x][i-1],g[x][i]+g[u][i-1])$ 所以代码如下: ```cpp #include<bits/stdc++.h> #define N 500005 #define inf 100000007 using namespace std; struct Edge{int u,v,next;}G[N*2]; int n,m,d; int val[N],head[N],f[N][25],g[N][25],tot=0; bool vis[N]; inline void addedge(int u,int v){ G[++tot].u=u;G[tot].v=v;G[tot].next=head[u];head[u]=tot; G[++tot].u=v;G[tot].v=u;G[tot].next=head[v];head[v]=tot; } void dfs(int u,int fa){ if(vis[u])f[u][0]=g[u][0]=val[u]; for(int i=1;i<=d;i++)g[u][i]=val[u]; g[u][d+1]=inf; for(int i=head[u];i;i=G[i].next){ int v=G[i].v;if(v==fa)continue; dfs(v,u); for(int j=d;j>=0;j--)g[u][j]=min(g[u][j]+f[v][j],g[v][j+1]+f[u][j+1]); for(int j=d;j>=0;j--)g[u][j]=min(g[u][j],g[u][j+1]); f[u][0]=g[u][0]; for(int j=1;j<=d+1;j++)f[u][j]+=f[v][j-1]; for(int j=1;j<=d+1;j++)f[u][j]=min(f[u][j],f[u][j-1]); } } inline int read(){ int f=1,x=0;char ch; do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9'); do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9'); return f*x; } int main(){ freopen("observer.in","r",stdin); freopen("observer.out","w",stdout); n=read();d=read(); for(int i=1;i<=n;i++)val[i]=read(); m=read();int x; for(int i=1;i<=m;i++){int x=read();vis[x]=true;} for(int i=1;i<n;i++){ int u=read(),v=read();addedge(u,v); } dfs(1,0); printf("%d\n",f[1][0]); } ```