• P4292 [WC2010]重建计划


    传送门

    首先这玩意儿很明显是分数规划,二分一个答案(mid),边权变为(w_i-mid),然后看看能不能找到一条路径长度在([L,R])之间,且边权总和非负,这个可以转化为求一条满足条件的边权最大的路径

    这个实际上可以用点分做,用单调队列可以优化到(O(nlog^2n)),然而我不知道为什么写挂掉了所以这里就不说了……

    我们设(f_{i,j})表示以(i)为根的子树中,从(i)向下走(j)步的链最长是多少。转移可以用长链剖分优化到均摊(O(1))。查询答案的话可以用线段树,这样的话复杂度就是(O(nlog^2n))

    不知道什么是长链剖分的可以看看蒟蒻的笔记

    然而不知道为什么长链剖分跑得并没有点分快

    //minamoto
    #include<bits/stdc++.h>
    #define ll long long
    #define inf 0x3f3f3f3f
    using namespace std;
    #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
    char buf[1<<21],*p1=buf,*p2=buf;
    int read(){
        int res,f=1;char ch;
        while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
        for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
        return res*f;
    }
    const int N=2e5+5,M=N<<2;const double eps=1e-4;
    int head[N],Next[N],ver[N],edge[N],tot;
    inline void add(int u,int v,int e){ver[++tot]=v,Next[tot]=head[u],head[u]=tot,edge[tot]=e;}
    int dfn[N],dep[N],son[N],w[N],n,L,R,cnt;
    double val[N],f[N],ans,mid;
    #define ls (p<<1)
    #define rs (p<<1|1)
    double s[M];
    inline void clear(){for(int i=0;i<M;++i)s[i]=-inf;}
    void update(int p,int l,int r,int x,double v){
        if(l==r)return (void)(s[p]=max(s[p],v));
        int mid=(l+r)>>1;
        x<=mid?update(ls,l,mid,x,v):update(rs,mid+1,r,x,v);
        s[p]=max(s[ls],s[rs]);
    }
    double query(int p,int l,int r,int ql,int qr){
        if(ql<=l&&qr>=r)return s[p];
        int mid=(l+r)>>1;double res=-inf;
        if(ql<=mid)res=max(res,query(ls,l,mid,ql,qr));
        if(qr>mid)res=max(res,query(rs,mid+1,r,ql,qr));
        return res;
    }
    void dfs(int u,int fa){
        for(int i=head[u];i;i=Next[i]){
            int v=ver[i];if(v==fa)continue;dfs(v,u);
            if(dep[v]>=dep[son[u]])son[u]=v,w[u]=edge[i];
            if(dep[v]+1>dep[u])dep[u]=dep[v]+1;
        }
    }
    void dfs1(int u,int fa){
    	dfn[u]=++cnt;if(son[u])dfs1(son[u],u);
    	for(int i=head[u];i;i=Next[i])if(ver[i]!=fa&&ver[i]!=son[u])dfs1(ver[i],u);
    }
    void split(int u,int fa){
        int pu=dfn[u];
        if(son[u])split(son[u],u),val[pu]=val[pu+1]+w[u]-mid;
        update(1,1,n,pu,f[pu]=-val[pu]);
        if(dep[u]>=L){
            double tmp=query(1,1,n,pu+L,pu+min(dep[u],R));
            ans=max(ans,tmp+val[pu]);
        }
        for(int i=head[u];i;i=Next[i]){
            int v=ver[i],pv=dfn[v];if(v==fa||v==son[u])continue;
            split(v,u);
            for(int j=0;j<=dep[v];++j){
                int l=pu+max(0,L-j-1),r=pu+min(dep[u],R-j-1);
                double tmp=query(1,1,n,l,r);
                ans=max(ans,tmp+val[pv]+val[pu]+f[pv+j]+edge[i]-mid);
            }
            for(int j=0;j<=dep[v];++j){
                double tmp=val[pv]+f[pv+j]+edge[i]-mid-val[pu];
                if(tmp>f[pu+j+1])update(1,1,n,pu+j+1,f[pu+j+1]=tmp);
            }
        }
    }
    inline bool check(){
        clear();
        ans=-inf,split(1,0);return ans>=eps;
    }
    int main(){
    //	freopen("testdata.in","r",stdin);
        n=read(),L=read(),R=read();
        for(int i=1,u,v,e;i<n;++i)u=read(),v=read(),e=read(),add(u,v,e),add(v,u,e);
        dfs(1,0),dfs1(1,0);
        double l=0,r=1e6;
        while(r-l>eps){
            mid=(l+r)/2;
            check()?l=mid:r=mid;
        }
        printf("%.3lf
    ",l);return 0;
    }
    
  • 相关阅读:
    [BZOJ3998]弦论
    [Arc062] Painting Graphs with AtCoDeer
    [BZOJ4819]新生舞会
    [BZOJ3091]城市旅行
    [BZOJ1494]生成树计数
    单独使用JDBC编程
    highcharts(前端报表生成)
    报表技术之PDF格式报表生成 ----JasperResport
    iText生成PDF 格式报表
    html基本代码书写
  • 原文地址:https://www.cnblogs.com/bztMinamoto/p/9949503.html
Copyright © 2020-2023  润新知