zoukankan      html  css  js  c++  java
  • bzoj4557侦查守卫

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4557

    树形DP。和“河流”有点像,也有一个类似“承诺”的东西。

      就是用 f 表示当前节点向下 j 层之下的需覆盖点已覆盖的费用。答案可以是 f [ root ] [0] 。(root是随便一个点)

        最好把当前节点看作第1层而不是第0层,这样就能用0表示当前节点的子树全覆盖了。

      为了转移,引入一个 g ,表示当前点在自己子树全覆盖的基础上可以向外覆盖 j 层。这时当前节点可以自然地看作第0层了。

        这也是为什么 f 表示的是“向下 j 层之下的点全覆盖”而不是“向下 j 层全覆盖”。就是为了方便转移。

          没错,因为如果记成“向下 j 层全覆盖”,那么记录下“还有一些没覆盖”这一状态也根本没用,因为兄弟节点都是从上往下帮自己覆盖的;

          而像这样记录成“向下还有 j 层没覆盖”,就有更多“把它们覆盖好”的机会,也方便转移等等,变得很顺畅!

    具体转移的时候,发现 g 的转移依赖 f (上一次的 f 值),而 f 的转移不依赖 g ,所以要先求g的值。

      可以用g[0]来更新 f [0] 的值,因为f [0] 是从当前节点的孩子们的 f 那里转移不过来的。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define ll long long
    using namespace std;
    const int N=5e5+5,D=25;const ll INF=0x7fffffff;
    int n,m,d,head[N],xnt;
    ll a[N],f[N][D],g[N][D];
    bool need[N];
    struct Edge{
        int next,to;
        Edge(int n=0,int t=0):next(n),to(t) {}
    }edge[N<<1];
    void add(int a,int b)
    {
        edge[++xnt]=Edge(head[a],b);head[a]=xnt;
        edge[++xnt]=Edge(head[b],a);head[b]=xnt;
    }
    void dfs(int cr,int fa)
    {
        f[cr][0]=g[cr][0]=need[cr]?a[cr]:0;//只有根节点时的状态 
        for(int j=1;j<=d;j++)g[cr][j]=a[cr];//初值 
        g[cr][d+1]=INF;
        for(int i=head[cr],v;i;i=edge[i].next)
        {
            if((v=edge[i].to)==fa)continue;
            dfs(v,cr);
            for(int j=0;j<=d;j++)g[cr][j]=min(g[cr][j]+f[v][j],f[cr][j+1]+g[v][j+1]);//从0开始 
            for(int j=d;j;j--)g[cr][j-1]=min(g[cr][j-1],g[cr][j]);
            f[cr][0]=g[cr][0];        //
            for(int j=1;j<=d;j++)f[cr][j]+=f[v][j-1];        //这个不要放在28行之前,因为该行要用到上一次的值 
            for(int j=1;j<=d;j++)f[cr][j]=min(f[cr][j],f[cr][j-1]);
        }
    }
    int main()
    {
        scanf("%d%d",&n,&d);for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
        scanf("%d",&m);int tmp;for(int i=1;i<=m;i++){scanf("%d",&tmp);need[tmp]=1;}
        int x,y;
        for(int i=1;i<n;i++)
        {
            scanf("%d%d",&x,&y);add(x,y);
        }
    //    memset(g,1,sizeof g);
        dfs(1,0);
        printf("%lld",f[1][0]);
        return 0;
    }
  • 相关阅读:
    SharedPreferences 使用
    activity在activity上面
    组合组件
    浏览器的渲染原理
    Node 入门<1>
    css 样式优先级
    z-index
    事件代理
    XSS && CRLF && property&attribute
    webpack 学习笔记
  • 原文地址:https://www.cnblogs.com/Narh/p/9140326.html
Copyright © 2011-2022 走看看