• bzoj 4557


    显然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
    ",g[1][0]);
        return 0;
    }
  • 相关阅读:
    多线程批量插入数据到数据库
    分分钟搞定redis
    Eclipse中JS文件红叉处理
    springmvc基础篇—处理图片静态资源文件
    springmvc基础篇—使用注解方式为前台提供数据
    springmvc基础篇—拆分配置文件
    springmvc基础篇—通过注解的方式去配置项目
    springmvc基础篇—修改默认的配置文件名称及位置
    springmvc基础篇—掌握三种控制器
    springmvc基础篇—掌握三种处理器
  • 原文地址:https://www.cnblogs.com/zhangleo/p/11140971.html
Copyright © 2020-2023  润新知