zoukankan      html  css  js  c++  java
  • [WC2010]重建计划 题解

    [WC2010]重建计划 题解

    Problem

    ​ 给定一棵树,边有边权,要求找到一条长度在([L,R])之间的链,使得链的总价值和除以链长最大

    Solution

    ​ 显然,这个式子的形式让人想到了01分数规划。于是根据01分数规划的套路,先二分一个答案

    ​ 考虑如何判断,现在等于把所有边都减去了一个(mid),要看有没有一条价值大于0的长度介于([L,R])的链

    ​ 是不是感觉点分治呼之欲出。的确,到了这里就是一个点分治的经典例题了。但是这不是这篇题解的重点

    ​ 显然DP也可做,记(f_{u,j})为在(u)子树中以(u)为端点的一条长度为(j)的链的最大价值,这个DP转移比较简单,但是复杂度是(O(n^2))

    ​ 我们发现这个DP的第二维状态与深度有关,故可以用长链剖分优化,统计答案时也可以用线段树优化,于是复杂度优化到了(O(nlog^2n))

    Code

    #include<bits/stdc++.h>
    #define inf 1e8
    #define DB double
    #define eps 1e-3
    using namespace std;
    int n,l,r,cnt,tim;
    DB ans,res,f[100005],g[100005];
    int head[100005],w[200005],to[200005],Next[200005];
    int dfn[100005],son[100005],dep[100005],sonw[100005];
    
    struct Segment_Tree{
    
        DB seg[400005];
    
        void clear(){
            memset(seg,0xc2,sizeof seg);
        }
    
        void change(int k,int l,int r,int pos,DB val){
            seg[k]=max(seg[k],val);
            if(l==r)
                return;
            int mid=l+r>>1;
            if(pos<=mid)
                change(k<<1  ,l,mid  ,pos,val);
            else
                change(k<<1|1,mid+1,r,pos,val);
            return;
        }
    
        DB query(int k,int l,int r,int wl,int wr){
            if(wl> r||l> wr)
                return -inf;
            if(wl<=l&&r<=wr)
                return seg[k];
            DB res=-inf;
            int mid=l+r>>1;
            res=max(res,query(k<<1  ,l,mid  ,wl,wr));
            res=max(res,query(k<<1|1,mid+1,r,wl,wr));
            return res;
        }
    
    }T;
    
    inline int read(){
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){
           if(ch=='-')f=-1;
           ch=getchar();
        }
        while(ch>='0'&&ch<='9'){
           x=(x<<1)+(x<<3)+ch-'0';
           ch=getchar();
        }
        return x*f;
    }
    
    inline void add(int u,int v,int p){
        w[++cnt]=p;to[cnt]=v;Next[cnt]=head[u];head[u]=cnt;
    }
    
    void dfs(int u,int fa){
        dep[u]=1;
        for(register int i=head[u];i;i=Next[i]){
            int v=to[i];
            if(v!=fa){
                dfs(v,u);
                dep[u]=max(dep[u],dep[v]+1);
                if(dep[v]>dep[son[u]]){
                    son[u]=v;
                    sonw[u]=w[i];
                }
            }
        }
        return;
    }
    
    void DP(int u,int fa,DB x){
        if(!dfn[u])
            dfn[u]=++tim;
        f[dfn[u]]=0;
        g[dfn[u]]=0;    
        if(son[u]){
            DP(son[u],u,x);
            f[dfn[u]]=x-g[dfn[u]+1]-sonw[u];
            g[dfn[u]]=g[dfn[u]+1]+sonw[u]-x;
        }
        T.change(1,1,n,dfn[u],f[dfn[u]]);
        for(register int i=head[u];i;i=Next[i]){
            int v=to[i];
            if(v==fa||v==son[u])
                continue;
            DP(v,u,x);
            for(register int j=1;j<=dep[v];++j){
                if(l<=dep[u]+j-1){
                    double now=T.query(1,1,n,dfn[u]+max(1,l-j),dfn[u]+min(r-j,dep[u]-1));
                    res=max(res,w[i]-x+f[dfn[v]+j-1]+g[dfn[v]]+g[dfn[u]]+now);
                }
            }
            for(register int j=1;j<=dep[v];++j){
                if(w[i]-x+f[dfn[v]+j-1]+g[dfn[v]]>g[dfn[u]]+f[dfn[u]+j]){
                    f[dfn[u]+j]=w[i]-x+f[dfn[v]+j-1]+g[dfn[v]]-g[dfn[u]];
                    T.change(1,1,n,dfn[u]+j,f[dfn[u]+j]);
                }
            }
        }
        if(dep[u]-1>=l)
            res=max(res,g[dfn[u]]+T.query(1,1,n,dfn[u]+l,dfn[u]+min(r,dep[u]-1)));
        return;
    }
    
    int check(DB x){
        res=-inf;
        T.clear();
        DP(1,0,x);
        return res>=0; 
    }
    
    int main(){
        
        n=read();l=read();r=read();
    
        for(register int i=2;i<=n;++i){
            int u=read(),v=read();
            int p=read();
            add(u,v,p);add(v,u,p);
        }
    
        dfs(1,0);
    
        DB L=0,R=1e6,ans=0;
        while(R-L>=eps/10){
            DB mid=(L+R)/2;
            if(check(mid)){
                ans=mid;
                L=mid;
            }
            else
                R=mid;
        }
    
        printf("%0.3lf
    ",ans);
    
        return 0;
    }
    
  • 相关阅读:
    bzoj3280
    bzoj3876
    洛谷 p1625
    bzoj1407
    bzoj1227
    bzoj1477 && exgcd学习笔记
    bzoj1345
    c#程序的config文件问题
    思维角度的重要性
    python异步初步窥探
  • 原文地址:https://www.cnblogs.com/zjy123456/p/13714844.html
Copyright © 2011-2022 走看看