• Weight the Tree (CF2,D) (贪心+分段处理+ 树上DP(邻居问题))


    思路:

    • 题目要 求好节点数最大时的最小值
    • 好节点数是前提条件,那么就分段考虑, 先看哪些点是好节点, 在看好节点时,如何让值最小
    • 贪心发现规律: 2个点之间不能同时好节点, 对于不是好节点的点,然他权值为1即可,好节点为儿子数
    • dp转移: dp[i][0], 无所谓儿子是好是坏, 当儿子权值一样时, 就以num[b][0],num[b][1]为标准来更新这个num[i][0],选其小的.  ------
    • p[i][1], 儿子必须全是不好
    • 注意初始化即可
    • 再来一个dfs 记录ans即可. 
    #include <bits/stdc++.h>
    using namespace std;
    #define ri register int 
    #define M 2000005
    
    int n,m;
    int T;
    vector <int> p[M];
    int vis[M];
    int dp[M][3];
    int num[M][3];
    int val[M];
    void dfs(int a)
    {
        vis[a]=1;
        for(ri i=0;i<p[a].size();i++)
        {
            int b=p[a][i];
            if(vis[b]) continue;
            dfs(b);
            
            if(dp[b][0]>dp[b][1])
            {
                dp[a][0]+=dp[b][0];
                num[a][0]+=num[b][0];
            }
            else if(dp[b][0]<dp[b][1]) dp[a][0]+=dp[b][1],num[a][0]+=num[b][1];
            else{
                dp[a][0]+=dp[b][0];
                num[a][0]+=min(num[b][0],num[b][1]);
            }
            num[a][1]+=num[b][0];    
            dp[a][1]+=dp[b][0];
        }
        num[a][0]++;
        num[a][1]+=p[a].size();    
        dp[a][1]++;
    }
    long long ans=0;
    void dfs2(int a,int t)
    {
        vis[a]=1;
        if(t==0)
        {
            ans++;
            val[a]=1;
            for(ri i=0;i<p[a].size();i++)
            {
                int b=p[a][i];
                if(vis[b]) continue;
                if(dp[b][0]>dp[b][1])
                {
                    dfs2(b,0);
                }
                else if(dp[b][0]<dp[b][1]) dfs2(b,1);
                else{
                    if(num[b][0]<=num[b][1]) dfs2(b,0);
                    else dfs2(b,1);
                }
            }
        }
        else
        {
            ans+=p[a].size();
            val[a]=p[a].size();
            for(ri i=0;i<p[a].size();i++)
            {
                int b=p[a][i];
                if(vis[b]) continue;
                dfs2(b,0);
            }
        }
    }
    
    int main(){
        ios::sync_with_stdio(false);
        cin.tie(0);cout.tie(0);
        
        cin>>n;
    
        for(ri i=1;i<n;i++)
        {
            int a,b;
            cin>>a>>b;
            p[a].push_back(b);
            p[b].push_back(a);
        }    
        if(n==2)
        {
            cout<<"2 2\n";
            cout<<"1 1";
            return 0;    
        }
        dfs(1);
        memset(vis,0,sizeof(vis));
                if(dp[1][0]>dp[1][1])
                {
                    dfs2(1,0);
                }
                else if(dp[1][0]<dp[1][1]) dfs2(1,1);
                else{
                    if(num[1][0]<=num[1][1]) dfs2(1,0);
                    else dfs2(1,1);
                }
        cout<<max(dp[1][0],dp[1][1])<<" "<<ans<<"\n";
        for(ri i=1;i<=n;i++) cout<<val[i]<<" ";
        
        
    }
    View Code

    后记:

    • 树上dp,关键是这个dp, 和 树上贡献的题 相互区分一下, 是一个包含关系. DP可以处理很多问题
    • 有前提条件就分段做
  • 相关阅读:
    Oracle Flashback技术
    管理Redo Log
    管理UNDO
    Oracle利用PIVOT和UNPIVOT进行行列转换
    如何在SQL CASE表达式中返回多个值
    第二十八节 jQuery事件委托
    第二十七节 jQuery弹框练习
    第二十六节 jQuery中的事件冒泡
    第二十五节 jQuery中bind绑定事件和解绑
    第二十四节 jQuery中的resize事件
  • 原文地址:https://www.cnblogs.com/Lamboofhome/p/16869074.html
Copyright © 2020-2023  润新知