ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

P1399 [NOI2013]快餐店

2019-09-17 11:06:18  阅读:296  来源: 互联网

标签:环上 快餐店 int sum P1399 back st NOI2013 dis


传送门

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

现在多了个环,先把非环上的直径(设为 $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\n") : printf(".0\n");
}
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;
}

 

标签:环上,快餐店,int,sum,P1399,back,st,NOI2013,dis
来源: https://www.cnblogs.com/LLTYYC/p/11532315.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有