zoukankan      html  css  js  c++  java
  • 【题解】POI2014FAR-FarmCraft

      这题首先手玩一下一下数据,写出每个节点修建软件所需要的时间和到达它的时间戳(第一次到达它的时间),不难发现实际上就是要最小化这两者之和。然后就想到:一棵子树内,时间戳必然是连续的一段区间,而如果将访问到子树根节点的时间看做0时,则是一段0~x的连续时间,与其他子树的分配无关。所以自然的联想到单独处理出dp[u]:以u为根节点,访问时间看做0的时候其中节点所需要的时间最大值。

      如何从dp[v]转移到dp[u]?首先随便给它们分配一个顺序,则每一个节点的最后最大值(原先的值建立在访问根节点的时间为0的基础上,但现在的根节点变成了原来根节点的父亲)=原来的dp值+分配的顺序所带来的时间差。我们分析应怎样分配这个顺序使得它们的最大值最小。

      我们有

            dp[u] = max{ dp[a] , dp[b] + size[a] + 2 };
            dp[u] = max{ dp[u] , max{ dp[b], dp[a] + size[b] + 2 }}; // size[x] 代表访问x子树的全部节点所需要的时间

      这个应该不难看出:实际上就是枚举了两种情况。那么如果第一次取得的值要小于第二次取得的值,我们就认为将第一个放在第二个前面是更优的。之所以+2,是因为由u->v的边还需要经过2次。

    // luogu-judger-enable-o2
    #include <bits/stdc++.h>
    using namespace std;
    #define maxn 600000
    #define int long long
    int n, a[maxn], size[maxn];
    int cnp = 1, dp[maxn], head[maxn];
    
    int read()
    {
        int x = 0;
        char c;
        c = getchar();
        while(c < '0' || c > '9') c = getchar();
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x;
    }
    
    struct node
    {
        int id, num, s;
    }P[maxn];
    
    struct edge
    {
        int to, last;
    }E[maxn * 2];
    
    bool cmp (node a, node b)
    {
        int p = max(a.num, b.num + a.s + 2);
        int q = max(b.num, a.num + b.s + 2);
        return p < q;
    }
    
    void add(int u, int v)
    {
        E[cnp].to = v, E[cnp].last = head[u]; head[u] = cnp ++;
    }
    
    void DP(int u, int fa)
    {
        if(u != 1) dp[u] = a[u];
        for(int i = head[u]; i; i = E[i].last)
        {
            int v = E[i].to;
            if(v == fa) continue;
            DP(v, u);
        }
        int tot = 0, last = 0;
        for(int i = head[u]; i; i = E[i].last)
            if(E[i].to != fa) P[++ tot] = (node) {E[i].to, dp[E[i].to], size[E[i].to]};
        if(tot) 
        {
            sort(P + 1, P + 1 + tot, cmp);
            for(int i = 1; i <= tot; i ++)
            {
                int v = P[i].id;
                dp[u] = max(dp[u], dp[v] + (size[u] + 1));
                size[u] += size[v] + 2;
            }
        }
    }
    
    signed main()
    {
        n = read();
        for(int i = 1; i <= n; i ++) a[i] = read();
        for(int i = 1; i < n; i ++)
        {
            int x = read(), y = read();
            add(x, y), add(y, x);
        }
        DP(1, 0);
        printf("%lld
    ", max(dp[1], (n - 1) * 2 + a[1]));
        return 0;
    }
  • 相关阅读:
    单元测试之PowerMock
    ClickHouse单机安装
    Oracle19C ADG主备切换问题处理
    oracle dbms_metadata.get_ddl的使用方法总结
    SCN太大引发ORA-600[2252]
    异步IO ORA-27090: Unable to reserve kernel resources for asynchronous disk I/O
    Oracle Linux 7.8 多路径(Multipath)+Udev绑定磁盘
    Oracle定期清理10日分区数据
    linux如何使用umount命令强制卸载文件系统
    临时表空间使用率和被谁占用情况
  • 原文地址:https://www.cnblogs.com/twilight-sx/p/8977300.html
Copyright © 2011-2022 走看看