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

    传送门

    基环树的题当然先考虑树上怎么搞,直接求个直径就完事了

    现在多了个环,先把非环上的直径(设为 $ans$)和环上节点 $x$ 到叶子的最大距离(设为 $dis[x]$)求出来

    考虑到对于某种最优的方案,环上一定有某条边完全不用走

    所以可以枚举断哪个边然后暴力,显然会 $T$ 飞

    考虑能够快速求出某条边断开后经过环的最大直径

    预处理 $A[i],B[i],C[i],D[i]$

    $A[i]$ 表示从环上某个固定的起点出发到达 $i$ 之前(包括 $i$) 的最长路径长度(这里路径包括到达叶子节点的路径)

    这个可以通过维护起点到当前距离再加上我们之前求出的 $dis$ 得到

    $B[i]$ 表示从环上那个固定的起点出发到达 $i$ 之前(包括 $i$)的节点中某两个叶子节点之间的最长距离

    这个即为 $sum[i]-sum[j]+dis[i]+dis[j]$,其中 $sum[i]$ 表示起点到 $i$ 的环上路程

    移项 $sum[i]+dis[i]+dis[j]-sum[j]$ ,动态维护当前 $dis[j]-sum[j]$ 的最大值即可

    $C[i]$ 表示从环上终点(其实就是那个固定的起点的另一边的第一个节点)出发......(剩下的和 $A[i]$表示的是一样的)

    $D[i]$ 同 $B[i]$ ,只是起点变成了终点,反过来了

    那么预处理之后,枚举断边 $i$ (注意边 $i$ 连接 $i$ 和 $i+1$)那么 $t=max(B[i],D[i+1],A[i]+C[i+1]+w)$

    其中 $w$ 是连接起点和终点的边的长度,那么 $A[i]+C[i+1]+w$ 其实就是跨过起点终点的距离

    最后 $ans=max(ans,min(t))$,注意 $t$ 取最小值,因为断边是在最优方案下,肯定要取最小

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<vector>
    using namespace std;
    typedef long long ll;
    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^48); ch=getchar(); }
        return x*f;
    }
    const int N=2e5+7;
    const ll INF=1e18;
    int n;
    int fir[N],from[N<<1],to[N<<1],val[N<<1],cntt;
    inline void add(int a,int b,int c) { from[++cntt]=fir[a]; fir[a]=cntt; to[cntt]=b; val[cntt]=c; }
    bool vis[N],ring[N],GG;
    vector <int> st,wt;
    vector <int> q,w;
    void find(int x,int fa,int ww)
    {
        st.push_back(x); wt.push_back(ww); vis[x]=1;
        for(int i=fir[x];i;i=from[i])
        {
            int &v=to[i]; if(v==fa) continue;
            if(vis[v])
            {
                while(st[st.size()-1]!=v)
                {
                    ring[st[st.size()-1]]=1;
                    q.push_back(st[st.size()-1]);
                    w.push_back(wt[wt.size()-1]);
                    st.pop_back(); wt.pop_back();
                }
                ring[v]=GG=1; q.push_back(v);
                w.push_back(val[i]); return;
            }
            find(v,x,val[i]); if(GG) return;
        }
        st.pop_back(); wt.pop_back();
    }
    ll dis[N],ans;
    void dfs(int x,int fa)
    {
        for(int i=fir[x];i;i=from[i])
        {
            int &v=to[i]; if(ring[v]||v==fa) continue;
            dfs(v,x); ans=max(ans,dis[x]+dis[v]+val[i]);
            dis[x]=max(dis[x],dis[v]+val[i]);
        }
    }
    ll A[N],B[N],C[N],D[N];
    void solve()
    {
        find(1,0,0); for(auto u: q) dfs(u,u);
        ll sum=0,mx=0; int len=q.size();
        A[0]=B[0]=dis[q[0]];
        for(int i=1;i<len;i++)
        {
            mx=max(mx,dis[q[i-1]]-sum); sum+=w[i-1];
            A[i]=max(A[i-1],sum+dis[q[i]]);
            B[i]=max(B[i-1],mx+sum+dis[q[i]]);
        }
        sum=mx=0; C[len-1]=D[len-1]=dis[q[len-1]];
        for(int i=len-2;i>=0;i--)
        {
            mx=max(mx,dis[q[i+1]]-sum); sum+=w[i];
            C[i]=max(C[i+1],sum+dis[q[i]]);
            D[i]=max(D[i+1],mx+sum+dis[q[i]]);
        }
        ll res=B[len-1];
        for(int i=0;i<len-1;i++)
        {
            ll t=max(max(B[i],D[i+1]), A[i]+C[i+1]+w[len-1] );
            res=min(res,t);
        }
        ans=max(ans,res);
        printf("%lld",ans>>1);
        ans&1 ? printf(".5
    ") : printf(".0
    ");
    }
    int main()
    {
        n=read(); int a,b,c;
        for(int i=1;i<=n;i++)
        {
            a=read(),b=read(),c=read();
            add(a,b,c); add(b,a,c);
        }
        solve();
        return 0;
    }
  • 相关阅读:
    131. Palindrome Partitioning
    130. Surrounded Regions
    129. Sum Root to Leaf Numbers
    128. Longest Consecutive Sequence
    125. Valid Palindrome
    124. Binary Tree Maximum Path Sum
    122. Best Time to Buy and Sell Stock II
    121. Best Time to Buy and Sell Stock
    120. Triangle
    119. Pascal's Triangle II
  • 原文地址:https://www.cnblogs.com/LLTYYC/p/11532315.html
Copyright © 2011-2022 走看看