传送门

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

现在多了个环,先把非环上的直径(设为 $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=,f=; char ch=getchar();
while(ch<''||ch>'') { if(ch=='-') f=-; ch=getchar(); }
while(ch>=''&&ch<='') { x=(x<<)+(x<<)+(ch^); ch=getchar(); }
return x*f;
}
const int N=2e5+;
const ll INF=1e18;
int n;
int fir[N],from[N<<],to[N<<],val[N<<],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]=;
for(int i=fir[x];i;i=from[i])
{
int &v=to[i]; if(v==fa) continue;
if(vis[v])
{
while(st[st.size()-]!=v)
{
ring[st[st.size()-]]=;
q.push_back(st[st.size()-]);
w.push_back(wt[wt.size()-]);
st.pop_back(); wt.pop_back();
}
ring[v]=GG=; 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(,,); for(auto u: q) dfs(u,u);
ll sum=,mx=; int len=q.size();
A[]=B[]=dis[q[]];
for(int i=;i<len;i++)
{
mx=max(mx,dis[q[i-]]-sum); sum+=w[i-];
A[i]=max(A[i-],sum+dis[q[i]]);
B[i]=max(B[i-],mx+sum+dis[q[i]]);
}
sum=mx=; C[len-]=D[len-]=dis[q[len-]];
for(int i=len-;i>=;i--)
{
mx=max(mx,dis[q[i+]]-sum); sum+=w[i];
C[i]=max(C[i+],sum+dis[q[i]]);
D[i]=max(D[i+],mx+sum+dis[q[i]]);
}
ll res=B[len-];
for(int i=;i<len-;i++)
{
ll t=max(max(B[i],D[i+]), A[i]+C[i+]+w[len-] );
res=min(res,t);
}
ans=max(ans,res);
printf("%lld",ans>>);
ans& ? printf(".5\n") : printf(".0\n");
}
int main()
{
n=read(); int a,b,c;
for(int i=;i<=n;i++)
{
a=read(),b=read(),c=read();
add(a,b,c); add(b,a,c);
}
solve();
return ;
}

P1399 [NOI2013]快餐店的更多相关文章

  1. P1399 [NOI2013] 快餐店 方法记录

    原题题面P1399 [NOI2013] 快餐店 题目描述 小 T 打算在城市 C 开设一家外送快餐店.送餐到某一个地点的时间与外卖店到该地点之间最短路径长度是成正比的,小 T 希望快餐店的地址选在离最 ...

  2. luogu P1399 [NOI2013]快餐店

    传送门 注意到答案为这个基环树直径\(/2\) 因为是基环树,所以考虑把环拎出来.如果直径不过环上的边,那么可以在环上每个点下挂的子树内\(dfs\)求得.然后如果过环上的边,那么环上的部分也是一条链 ...

  3. bzoj 3242: [Noi2013]快餐店 章鱼图

    3242: [Noi2013]快餐店 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 266  Solved: 140[Submit][Status] ...

  4. bzoj3242 [Noi2013]快餐店

    Description 小T打算在城市C开设一家外送快餐店.送餐到某一个地点的时间与外卖店到该地点之间最短路径长度是成正比的,小T希望快餐店的地址选在离最远的顾客距离最近的地方. 快餐店的顾客分布在城 ...

  5. 3242: [Noi2013]快餐店 - BZOJ

    Description 小T打算在城市C开设一家外送快餐店.送餐到某一个地点的时间与外卖店到该地点之间最短路径长度是成正比的,小T希望快餐店的地址选在离最远的顾客距离最近的地方. 快餐店的顾客分布在城 ...

  6. 动态规划:NOI2013 快餐店

    Description 小 T打算在城市C开设一家外送快餐店.送餐到某一个地点的时间与外卖店到该地点之间最短路径长度是成正比的,小T希望快餐店的地址选在离最远的顾客距离最近 的地方. 快餐店的顾客分布 ...

  7. NOI2013 快餐店

    http://uoj.ac/problem/126 总的来说,还是很容易想的,就是有点恶心. 首先,很明显只有一个环. 我们先找出这个环,给各棵树编号id[i],然后各棵树分别以环上的点为根,求出每个 ...

  8. bzoj 3242: [Noi2013]快餐店

    Description 小T打算在城市C开设一家外送快餐店.送餐到某一个地点的时间与外卖店到该地点之间最短路径长度是成正比的,小T希望快餐店的地址选在离最远的顾客距离最近的地方. 快餐店的顾客分布在城 ...

  9. BZOJ3242/UOJ126 [Noi2013]快餐店

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...

随机推荐

  1. PTA 刷题与Z老师的头发

    刷题与Z老师的头发 (10 分) 在Pintia上,每天Z老师出题.小盆友们刷题.Z老师的头发遵从以下规律: 1.每天生长出60根头发: 2.每出一道题,减少20根头发: 3.每天结束时统计累积做题情 ...

  2. php 将几个变量合为数组,变量名和值对应

    <?php $firstname = "Bill"; $lastname = "Gates"; $age = "60"; $resul ...

  3. [CSP-S模拟测试]:小盆友的游戏(数学 or 找规律)

    题目传送门(内部题110) 输入格式 第一行一个整数$N$,表示小盆友的个数. 第二行$N$个整数$A_i$,如果$A_i=-1$表示$i$目前是自由身,否则$i$是$A_i$的跟班. 输出格式 一个 ...

  4. 移动端 iphone手机在中文情况下不执行keyup事件

    问题:移动端 在

  5. XMLHttpRequest 对象属性参数参考

    readyState:提供当前 HTML 的就绪状态. readyState可能返回的值: 0:请求未初始化(还没有调用 open()). 1:请求已经建立,但是还没有发送(还没有调用 send()) ...

  6. redis深度历险:核心原理与应用实践--笔记

  7. 数字 kotlin (1)

    数字Kotlin 处理数字在某种程度上接近 Java,但是并不完全相同.例如,对于数字没有隐式拓宽转换(如 Java 中 int 可以隐式转换为 long ——译者注),另外有些情况的字面值略有不同. ...

  8. leetcode-easy-listnode-141 Linked List Cycle

    mycode  98.22% # Definition for singly-linked list. # class ListNode(object): # def __init__(self, x ...

  9. C# hook WndProc

    在当前窗口里重载WndProc,只能捕获到当前WinForm窗口的消息 protected override void WndProc(ref Message m) { if (m.Msg == WM ...

  10. 分组 vs 联合

    // 分组 function groupBy(groups) { return groups.reduce((pre, cur) => { pre[cur.groupId] = (pre[cur ...