zoukankan      html  css  js  c++  java
  • 4557: [JLoi2016]侦察守卫

    4557: [JLoi2016]侦察守卫

    链接

    分析:

      因为D比较小,所设状态f[i][j]表示子树i内,从i往下第j层及第j层以下都覆盖了的最小代价,g[i][j]表示覆盖完子树内所有点,还可以往上覆盖j层的最小花费。

      g的转移从子树内转移的时候,可以覆盖其他子树内的点, f数组直接求和即可。

      最后要对g维护一下后缀最小值,对i维护前缀最小值。因为往上覆盖i+1的,一定可以更新往上覆盖i层的;往下有i层未覆盖的,一定可以更新往下有i-1层未覆盖的。

    代码:

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<iostream>
    #include<cmath>
    #include<cctype>
    #include<set>
    #include<queue>
    #include<vector>
    #include<map>
    using namespace std;
    typedef long long LL;
    
    inline int read() {
        int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
        for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
    }
    
    const int N = 500005;
    struct Edge{ int to, nxt; } e[N << 1];
    int head[N], fa[N], En, D;
    LL f[N][22], g[N][22], w[N];
    bool ext[N];
    
    inline void add_edge(int u,int v) {
        ++En; e[En].to = v, e[En].nxt = head[u]; head[u] = En;
        ++En; e[En].to = u, e[En].nxt = head[v]; head[v] = En;
    }
    
    void dfs(int u) {
        if (ext[u]) f[u][0] = g[u][0] = w[u];
        for (int j = 1; j <= D; ++j) g[u][j] = w[u];
        g[u][D + 1] = 1e9;
        for (int i = head[u]; i; i = e[i].nxt) {
            int v = e[i].to;
            if (v == fa[u]) continue;
            fa[v] = u;
            dfs(v);
            for (int j = D; ~j; --j) g[u][j] = min(g[u][j] + f[v][j], g[v][j + 1] + f[u][j + 1]);
            for (int j = D; ~j; --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]);
        }
    }
    
    int main() {
        int n = read(); D = read();
        for (int i = 1; i <= n; ++i) w[i] = read();
        int m = read();
        for (int i = 1; i <= m; ++i) ext[read()] = 1;
        for (int i = 1; i < n; ++i) add_edge(read(), read());
        dfs(1);
        cout << f[1][0];
        return 0;
    }
  • 相关阅读:
    海龟交易
    暑假攻略:怎样让孩子过一个充实又省钱的假期
    值得追随
    在哪里能找的你想要的答案?
    顺势加仓策略
    交易中 你的加仓策略是怎样的?背后的逻辑是什么?
    驻守深寒:寻找那些有效地关键K线
    统计相关
    求助Ubuntu16.10如何设置默认启动为字符界面
    【Linux系列】Ubuntu ping通,xshell无法连接
  • 原文地址:https://www.cnblogs.com/mjtcn/p/10460101.html
Copyright © 2011-2022 走看看