zoukankan      html  css  js  c++  java
  • luoguP5521 [yLOI2019] 梅深不见冬

    luoguP5521 [yLOI2019] 梅深不见冬

    Description

    给定一棵 n个节点的树,在树上行走,每次要么选择一个没有到达过的子节点,要么返回父节点。想要在一个节点 u 放上梅花当且仅当 u 的任意子节点 v 都被放上了 w​ 朵梅花。在任意时刻可以收回任意节点的梅花。对于每个节点,求如果想在这个节点放梅花,则至少需要准备多少梅花。

    Solution

    容易注意到叶子节点的答案一定是本身的权值

    而非叶节点一定是由下面的点限制的

    因此考虑自底向上处理

    显然对于一个节点i,他的答案最优是自身权值和所有儿子权值之和

    不能达到最优在于有可能儿子所需的答案更大

    于是考虑保证每个儿子都能填数,显然儿子所需的答案已经处理出来了

    显然当你填了一个数后他的前置节点就不需要再放数了,也就是说这一部分可以在儿子间重复利用

    很显然前置最多的那个点的前置的梅花一定可以反复放在其他儿子上

    所以说答案一定不会大于这个点本身的值加上儿子的值再加上最多的前置

    但是这一部分前置有一部分可以回收放在节点的权值上

    所以考虑按前置排序,每次保证当前前置的时候尽可能多的放在节点上

    答案显然更优

    #include<bits/stdc++.h>
    
    using namespace std;
    
    inline int read()
    {
        int f = 1,x = 0;
        char ch;
        do
        {
            ch = getchar();
            if(ch == '-') f = -1;
        }while(ch < '0'|| ch > '9');
        do
        {
            x = (x<<3) + (x<<1) + ch - '0';
            ch = getchar();
        }while(ch >= '0'&&ch <= '9');
        return f*x;
    }
    
    const int MAXN = 100000 + 10;
    
    int n;
    int ans[MAXN],f[MAXN],g[MAXN];
    int w[MAXN];
    vector<int>G[MAXN];
    vector<pair<int,int> >son[MAXN];
    
    inline void dfs(int x)
    {
        ans[x] = w[x];
        if(!G[x].size()) return;
        for(int i=0;i<G[x].size();i++)
        {
            int v = G[x][i];
            dfs(v);
            son[x].push_back(make_pair(ans[v] - w[v],v));
        }
        sort(son[x].begin(),son[x].end());
        int res = 0;
        int sum = 0;
        for(int i=son[x].size()-1;i>=0;i--)
        {
            int v = son[x][i].second;
            if(res < ans[v])
            {
                sum += (ans[v] - res);
                res = ans[v] - w[v];
            }
            else res -= w[v];
        }
        if(res < w[x]) sum += (w[x] - res);
        ans[x] = sum;
    //    cout << x << " " << f[x] << " " << ans[x] << " " << maxv << " " << w[maxi] << endl;
        return;
    }
    
    int main()
    {
        n = read();
        for(int i=2;i<=n;i++)
        {
            G[read()].push_back(i);
        }
        for(int i=1;i<=n;i++) w[i] = read();
        dfs(1);
        for(int i=1;i<=n;i++) printf("%d ",ans[i]);
    }
  • 相关阅读:
    Linux内核网络协议栈优化总纲
    Java实现 蓝桥杯VIP 算法训练 连续正整数的和
    Java实现 蓝桥杯VIP 算法训练 连续正整数的和
    Java实现 蓝桥杯VIP 算法训练 寂寞的数
    Java实现 蓝桥杯VIP 算法训练 寂寞的数
    Java实现 蓝桥杯VIP 算法训练 学做菜
    Java实现 蓝桥杯VIP 算法训练 学做菜
    Java实现 蓝桥杯VIP 算法训练 判断字符位置
    Java实现 蓝桥杯VIP 算法训练 判断字符位置
    Java实现 蓝桥杯VIP 算法训练 链表数据求和操作
  • 原文地址:https://www.cnblogs.com/wlzs1432/p/13783002.html
Copyright © 2011-2022 走看看