zoukankan      html  css  js  c++  java
  • 2020牛客暑期多校训练营(第九场)B

    Description

    有一棵 (n) 个点的树,从 (1) 号点出发,经过一条边的时候会减少一定的 HP,每条边最多只能经过两次。首次到达某个点 (i) 会增加 (a[i]) 点 HP。求初始 HP 至少为多少才能保证存在一种能遍历所有点并回到原点的方案且整个过程中的 HP 非负。

    Solution

    不妨设访问 (i) 的子树的代价总和为 (s[i]),设访问 (i) 的子树过程中可能出现的最小 HP 的最大值(可能是负数)为 (f[i]),则转移时需要枚举访问各个子树的顺序。

    考虑引入临项交换排序的思想,对于 (i,j=i+1),如果 (i o j)(j o i) 优,那么一定有 (min(f_j, s_j+f_i) = min (f_i,s_i+f_j))

    为了能分离出排序使用的关键字,暴力展开上式,发现可以将所有孩子分成 (A={i | i ge 0}, B=E-A) 两部分,那么显然对于 (a in A,b in B)(a o b) 是更优的,于是只需要考虑 (A,B) 各自内部的顺序。根据展开结果容易得出,(A) 内需要 (f_i > f_j)(B) 内需要 (s_i - f_i > s_j - f_j)。实际实现时可以放在一起处理。

    #include <bits/stdc++.h>
    using namespace std;
    
    #define int long long 
    const int N = 1000005;
    
    int f[N],s[N],a[N],vis[N],n,m,faw[N];
    
    vector <pair<int,int>> g[N];
    
    int t1,t2,t3;
    
    void clear()
    {
        for(int i=1;i<=n;i++)
        {
            f[i]=s[i]=a[i]=vis[i]=faw[i]=0;
            g[i].clear();
        }
    }
    
    bool cmp(int i,int j)
    {
        if(s[i]>=0 && s[j]<0) return 1;
        if(s[i]>=0)
        {
            return f[i]>f[j];
        }
        if(s[j]<0)
        {
            return s[i]+f[j]>s[j]+f[i];
        }
        return 0;
    }
    
    
    void dfs(int p)
    {
        vis[p]=1;
        s[p]=a[p];
        vector <int> vec;
        for(auto pr:g[p])
        {
            int q=pr.first,w=pr.second;
            if(vis[q]==0)
            {
                dfs(q);
                s[q]-=w*2;
                f[q]-=w;
                f[q]=min(f[q],s[q]);
                vec.push_back(q);
            }
        }
        sort(vec.begin(),vec.end(),cmp);
        for(auto i:vec)
        {
            f[p]=min(f[p],s[p]+f[i]);
            s[p]+=s[i];
        }
    }
    
    
    signed main()
    {
        ios::sync_with_stdio(false);
    
        int t;
        cin>>t;
        while(t--)
        {
            cin>>n;
            for(int i=1;i<=n;i++) cin>>a[i];
            for(int i=1;i<n;i++)
            {
                cin>>t1>>t2>>t3;
                g[t1].push_back({t2,t3});
                g[t2].push_back({t1,t3});
            }
            dfs(1);
            cout<<max(0ll,-f[1])<<endl;
            clear();
        }
        return 0;
    }
    
  • 相关阅读:
    Golang 函数
    关于Golang中database/sql包的学习
    golang第三方库goconfig的使用
    golang []byte和string相互转换
    golang xorm应用
    PHPExcel 导入
    贝叶斯定理
    myFocus 焦点图/轮播插件
    Maven 安装与使用(一)
    Javascript -- toFixed()函数
  • 原文地址:https://www.cnblogs.com/mollnn/p/13770240.html
Copyright © 2011-2022 走看看