zoukankan      html  css  js  c++  java
  • luogu P1399 [NOI2013]快餐店

    传送门

    注意到答案为这个基环树直径(/2)

    因为是基环树,所以考虑把环拎出来.如果直径不过环上的边,那么可以在环上每个点下挂的子树内(dfs)求得.然后如果过环上的边,那么环上的部分也是一条链,考虑拆环为链,现在问题是一条链,每个点往下延伸若干长度,问最远的距离.每个点往下最长的长度可以随便预处理,然后最长的路径一定是两个点以及往下延伸的路径+在链上两点之间的路径,也可以看成这条长链+前面那个点往下的链-前面链的部分+后面那个点往下的链-后面链的部分,所以可以维护两棵线段树,分别维护 点往下的链-前面链的部分 以及 点往下的链-后面链的部分,然后第一棵树的最大值和第二棵的最大值加长链长度就可以更新答案.然后每次删掉最前面那个点,加到链的最后面,两个线段树分别区间修改即可.

    注意如果第一棵树的前缀最大值是最后一个点,那么要用第二棵树最大值+第一棵树到第二棵树最大值前面一位的前缀最大值更新答案

    #include<bits/stdc++.h>
    #define LL long long
    #define uLL unsigned long long
    #define il inline
    
    using namespace std;
    const LL N=1e5+10,mod=1e9+7;
    il LL rd()
    {
        LL x=0,w=1;char ch=0;
        while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();}
        while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
        return x*w;
    }
    int to[N<<1],nt[N<<1],w[N<<1],hd[N],tot=1;
    void add(int x,int y,int z)
    {
        ++tot,to[tot]=y,nt[tot]=hd[x],w[tot]=z,hd[x]=tot;
        ++tot,to[tot]=x,nt[tot]=hd[y],w[tot]=z,hd[y]=tot;
    }
    int n,m,st[N][2],tp;
    LL cr[N][2],de[N],dp[N];
    bool v[N],ic[N];
    bool d1(int x,int ffa)
    {
        if(v[x])
        {
            while(tp)
            {
                cr[++m][0]=st[tp][0],cr[m][1]=st[tp][1];
                ic[st[tp][0]]=1;
                if(st[tp][0]==x) break;
                --tp;
            }
            return 1;
        }
        v[x]=1,st[++tp][0]=x;
        for(int i=hd[x];i;i=nt[i])
        {
            int y=to[i];
            if(y==ffa) continue;
            st[tp][1]=w[i];
            if(d1(y,x)) return 1;
        }
        --tp;
        return 0;
    }
    void d2(int x,int ffa)
    {
        st[++tp][0]=x;
        dp[x]=de[x];
        for(int i=hd[x];i;i=nt[i])
        {
            int y=to[i];
            if(ic[y]||y==ffa) continue;
            de[y]=de[x]+w[i],d2(y,x),dp[x]=max(dp[x],dp[y]);
        }
    }
    #define mid ((l+r)>>1)
    struct SegmentTree
    {
        LL s[N<<3],tg[N<<3];
        int lc[N<<3];
        void ad(int o,LL x){s[o]+=x,tg[o]+=x;}
        void psup(int o){s[o]=max(s[o<<1],s[o<<1|1]),lc[o]=s[o<<1]>=s[o<<1|1]?lc[o<<1]:lc[o<<1|1];}
        void psdn(int o){if(tg[o]) ad(o<<1,tg[o]),ad(o<<1|1,tg[o]),tg[o]=0;}
        void modif(int o,int l,int r,int ll,int rr,LL x)
        {
            if(ll<=l&&r<=rr){ad(o,x);return;}
            psdn(o);
            if(ll<=mid) modif(o<<1,l,mid,ll,rr,x);
            if(rr>mid) modif(o<<1|1,mid+1,r,ll,rr,x);
            psup(o);
        }
        void modif(int o,int l,int r,int lx,LL x)
        {
            if(l==r){ad(o,x);return;}
            psdn(o);
            if(lx<=mid) modif(o<<1,l,mid,lx,x);
            else modif(o<<1|1,mid+1,r,lx,x);
            psup(o);
        }
        LL quer(int o,int l,int r,int ll,int rr,int &lx)
        {
            if(ll<=l&&r<=rr) {lx=lc[o];return s[o];}
            psdn(o);
            LL a1=-(1ll<<50),a2=-(1ll<<50);
            int l1=0,l2=0;
            if(ll<=mid) a1=quer(o<<1,l,mid,ll,rr,l1);
            if(rr>mid) a2=quer(o<<1|1,mid+1,r,ll,rr,l2);
            psup(o);
            lx=a1>=a2?l1:l2;
            return max(a1,a2);
        }
        void bui(int o,int l,int r)
        {
            if(l==r){lc[o]=l;return;}
            bui(o<<1,l,mid),bui(o<<1|1,mid+1,r);
            psup(o);
        }
    }tr1,tr2;
    
    int main()
    {
        n=rd();
        for(int i=1;i<=n;++i)
        {
            int x=rd(),y=rd(),z=rd();
            add(x,y,z);
        }
        d1(1,0);
        LL dn=0;
        for(int i=1;i<=m;++i)
        {
            tp=0;
            d2(cr[i][0],0);
            LL nw=dp[cr[i][0]];
            //printf("%lld %lld
    ",nw,cr[i][1]);
            int x=0;
            while(tp)
            {
                if(de[st[tp][0]]==nw) {x=st[tp][0];break;}
                --tp;
            }
            tp=0;
            ic[cr[i][0]]=0;
            de[x]=0,d2(x,0);
            ic[cr[i][0]]=1;
            dn=max(dn,dp[x]);
            dp[cr[i][0]]=nw;
        }
        LL ln=0,ans=1ll<<50;
        tr1.bui(1,1,m+m+1),tr2.bui(1,1,m+m+1);
        for(int ll=1-m,rr=0;rr<m+m;)
        {
            if(ll>0) tr1.modif(1,1,m+m+1,ll,rr,cr[ll%m+1][1]),ln-=cr[ll%m+1][1];
            ++ll;
            if(rr>0) ln+=cr[rr%m+1][1],tr2.modif(1,1,m+m+1,max(ll,1),rr,-cr[rr%m+1][1]);
            ++rr;
            tr1.modif(1,1,m+m+1,rr,dp[cr[(rr-1)%m+1][0]]-ln),tr2.modif(1,1,m+m+1,rr,dp[cr[(rr-1)%m+1][0]]);
            if(ll>0)
            {
                int lx=0,ee;
                LL dt=ln+tr1.quer(1,1,m+m+1,ll,rr,lx);
                if(lx<rr) dt+=tr2.quer(1,1,m+m+1,lx+1,rr,ee);
                LL d2=ln+tr2.quer(1,1,m+m+1,ll,rr,lx);
                if(lx>ll) d2+=tr1.quer(1,1,m+m+1,ll,lx-1,ee);
                ans=min(ans,max(dt,d2));
            }
        }
        ans=max(ans,dn);
        printf("%lld.%lld
    ",ans>>1,5*(ans&1));
        return 0;
    }
    
  • 相关阅读:
    CSDNReader(android客户端)发布!!
    linux下的C语言快速学习—从1+1开始。
    linux下的C语言快速学习—进程和文件
    ListView动态加载数据分页(使用Handler+线程和AsyncTask两种方法)
    CSDN阅读器(android版)开发总结
    算法实现将一个输入的数字颠倒(输入12345>54321)
    linux下的C语言快速学习—计算机体系结构基础简单了解
    实现一个字符串查找子串的函数
    .net4.0面向对象学习笔记—数据类型
    装饰器模式
  • 原文地址:https://www.cnblogs.com/smyjr/p/10802451.html
Copyright © 2011-2022 走看看