码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj 4557

时间:2019-07-05 22:39:10      阅读:103      评论:0      收藏:0      [点我收藏+]

标签:理解   tac   template   get   color   假设   因此   设计   code   

显然dp

考虑每个节点需要考虑的问题:

第一:这个点下面被覆盖的情况

第二:这个点对上面的贡献

据此我们设计状态:

$f[i][j]$表示以$i$为根节点的子树中已经覆盖好了下面剩余层,只剩下上面$j$层还没覆盖

$g[i][j]$表示以$i$为根节点的子树中每个点都被覆盖了,而且还能向上覆盖$j$层

那么考虑转移:设根节点为$x$,其某一个子节点为$to$

首先对于$g$:$g[x][j]=min(g[x][j]+f[to][j],f[x][j+1]+g[to][j+1])$

这个转移的原理:先假设这个子节点需要被覆盖,那么根节点必须覆盖好之前的部分,然后用$j$的贡献去覆盖这个子节点下面的部分

然后假设这个子节点可以对上面产生贡献,那么之前的部分就不需要覆盖好,允许有相同的层数未被覆盖

接下来对于$f$:$f[x][j]=\sum f[to][j-1]$

这个好理解,下面的向上转移少覆盖的多了一层就行了嘛

然后考虑互相之间的贡献,有:$f[x][j]=min(f[x][j],f[x][j-1])$,$g[x][j]=min(g[x][j],g[x][j+1])$即我们可以用更小的代价换取更好的效果

因此本题结束

#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
#define ll long long
using namespace std;
vector <int> v[500005];
int n,m,d;
bool vis[500005];
ll w[500005];
ll f[500005][25],g[500005][25];
void dfs(int x,int fx)
{
    if(vis[x])f[x][0]=g[x][0]=w[x];
    for(int i=1;i<=d;i++)g[x][i]=w[x];
    g[x][d+1]=f[x][d+1]=0x3f3f3f3f3f3f3f3fll;
    for(int i=0;i<v[x].size();i++)
    {
        int to=v[x][i];
        if(to==fx)continue;
        dfs(to,x);
    }
    for(int i=0;i<v[x].size();i++)
    {
        int to=v[x][i];
        if(to==fx)continue;
        for(int j=0;j<=d;j++)g[x][j]=min(g[x][j]+f[to][j],f[x][j+1]+g[to][j+1]);
        for(int j=d;j>=0;j--)g[x][j]=min(g[x][j],g[x][j+1]);
        f[x][0]=g[x][0];
        for(int j=1;j<=d;j++)f[x][j]+=f[to][j-1];
        for(int j=1;j<=d;j++)f[x][j]=min(f[x][j],f[x][j-1]);
    }
}
template <typename T>inline void read(T &x)
{
    T f=1,c=0;char ch=getchar();
    while(ch<0||ch>9){if(ch==-)f=-1;ch=getchar();}
    while(ch>=0&&ch<=9){c=c*10+ch-0;ch=getchar();}
    x=c*f;
}
int main()
{
    read(n),read(d);
    for(int i=1;i<=n;i++)read(w[i]);
    read(m);
    for(int i=1;i<=m;i++)
    {
        int x;read(x);
        vis[x]=1;
    }
    for(int i=1;i<n;i++)
    {
        int x,y;
        read(x),read(y);
        v[x].push_back(y),v[y].push_back(x);
    }
    dfs(1,0);
    printf("%lld\n",g[1][0]);
    return 0;
}

 

bzoj 4557

标签:理解   tac   template   get   color   假设   因此   设计   code   

原文地址:https://www.cnblogs.com/zhangleo/p/11140971.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!