zoukankan      html  css  js  c++  java
  • LuoguP6748 『MdOI R3』Fallen Lord 树形DP+set

    首先,肯定没有不合法情况(每条边的权值都赋值为 $1$ 就一定合法)   

    然后对于一条边 $(x,y)$ 来说,只可能有 3 种取值.  

    1. 取 $a[x]$ 

    2. 取 $a[y]$ 

    3. 取 $m$    

    然后转化成这一步后就可以进行树形 DP 了.  

    令 $f[x][0],f[x][1]$ 分别表示以 $x$ 为根的子树,且 $x$ 与 $x$ 父亲连边的边权小于等于 $a[x]$/大于 $a[x]$ 的最大权和.     

    这个裸做的话是一个 $O(n^2)$ 的树形背包.  

    但是我们发现这个问题中所有物品的体积都是 $1$,那么我们就可以先贪心选取一个儿子 $y$ 的最优决策点.   

    如果该决策点没有让边权小于等于 $a[x]$ ,就把差量扔进一个 set 里,贪心取出需要补齐的部分就行了.  

    代码: 

    #include <cstdio>
    #include <set>
    #include <vector>
    #include <cstring>
    #include <algorithm> 
    #define N 500009  
    #define ll long long 
    #define setIO(s) freopen(s".in","r",stdin) 
    using namespace std;  
    const ll inf=1000000000;    
    int n,m,edges;  
    ll f[N][2];  
    int deg[N]; 
    int a[N],hd[N],to[N<<1],nex[N<<1];  
    void add(int u,int v) { 
        nex[++edges]=hd[u]; 
        hd[u]=edges,to[edges]=v; 
    }
    multiset<ll>se[N];          
    multiset<ll>::iterator it;  
    void dfs(int x,int ff) {  
        int det=deg[x]/2+1,cnt=0;      
        // f[x][0] : det-1  
        // f[x][1] : det     
        f[x][0]=f[x][1]=0;     
        for(int i=hd[x];i;i=nex[i]) { 
            int y=to[i];   
            if(y==ff) continue;  
            dfs(y,x);     
            ll cur=max(f[y][0]+a[y],f[y][1]+m);       
            f[x][0]+=cur;  
            f[x][1]+=cur;   
            if(a[x]>=a[y]) { 
                if(f[y][1]+m==cur&&m>a[x]) {             
                    se[x].insert(-(max(f[y][0]+a[y],f[y][1]+a[x])-cur));           
                }  
                else ++cnt;    
            } 
            else {
                se[x].insert(-(max(f[y][0]+a[x],f[y][1]+a[x])-cur));    
            }
        }    
        int k0=det-1,k1=det;      
        if(cnt+se[x].size()>=k0) {    
            it=se[x].begin();   
            for(int i=1;i<=k0-cnt;++i)   {  
                f[x][0]-=(*it);              
                it++;   
            }
        }       
        else f[x][0]=-inf;   
        if(cnt+se[x].size()>=k1) {  
            it=se[x].begin();  
            for(int i=1;i<=k1-cnt;++i)   {   
                f[x][1]-=(*it); 
                it++;   
            }
        }  
        else f[x][1]=-inf; 
        se[x].clear();   
        if(deg[x]==1&&ff) {   
            f[x][0]=0;   
            f[x][1]=-inf;   
        }   
    }   
    int main() {
        // setIO("input");   
        scanf("%d%d",&n,&m);   
        for(int i=1;i<=n;++i) { 
            scanf("%d",&a[i]); 
            a[i]=min(a[i],m);    
        }   
        int x,y,z; 
        for(int i=1;i<n;++i) { 
            scanf("%d%d",&x,&y); 
            add(x,y);  
            add(y,x);   
            ++deg[x]; 
            ++deg[y];  
        }         
        dfs(1,0);   
        printf("%lld
    ",f[1][1]);      
        return 0; 
    }
    

      

  • 相关阅读:
    SSH 错误解决案例1:Read from socket failed: Connection reset by peer
    vmware已经全面支持open-vm-tools
    RHEL7.1 安装openstack juno 一个BUG
    web快速开发框架 WebBuilder 8.7发布
    2019年如何选择合适的快速开发平台和框架
    快速开发平台 WebBuilder 8.6发布
    快速开发平台比较
    快速开发平台 WebBuilder 8.4 发布
    快速开发平台 WebBuilder 8 发布
    快速开发平台WebBuilder中ExtJS表格的增删改查
  • 原文地址:https://www.cnblogs.com/guangheli/p/13469823.html
Copyright © 2011-2022 走看看