——来自一个失去梦想的咸鱼miaom
考虑海蜇基环树的一般套路,在确定快餐店位置的情况下,最优解中环上必有一条边是废的。思考枚举这条边,我们需要在最快的时间求剩余部分的直径。当前答案就是直径/2,证明非常简单,就离快餐店最远的点一定是直径端点。这个东西可以通过双指针单调队列维护,达到O(n)复杂度。然后我就失去了梦想,直接线段树水过了。
线段树做法如下:先搞出那个环,重复一遍变成序列问题,询问一个区间的直径。有一种情况直径不在环上,可以预处理。另一种情况至于环上点子树最深的点有关,使用线段树维护那个点的深度±在环中的位置区间合并,具体见代码~
至于怎么搞环,不是重点,一波dfs即可(其实拓扑排序也可以)。
#include<bits/stdc++.h>
#define N 200005
#define ll long long
using namespace std;
ll n,x,y,z,m;
ll fst[N],to[N*2],nxt[N*2],len[N],l;
ll vis[N],fa[N],flag,flag1,flag2,fl[N];
ll a[N];ll b[N],d[N],M1[N],Mx[N],dep[N],vl[N],vr[N],Ans,ly;
void link(ll x,ll y,ll z)
{
to[++l]=y;len[l]=z;nxt[l]=fst[x];fst[x]=l;
to[++l]=x;len[l]=z;nxt[l]=fst[y];fst[y]=l;
}
void dfs(ll x)
{
//cout<<x<<endl;
vis[x]=1;
for (ll i=fst[x];i;i=nxt[i])
if (to[i]!=fa[x])
{
if (vis[to[i]])
{
if (!flag)
flag=x,flag1=to[i],flag2=len[i];
}
else
{
dep[to[i]]=dep[x]+len[i];
fa[to[i]]=x;
dfs(to[i]);
//fl[x]+=fl[to[i]];
}
}
}
void Dfs(ll x)
{
Mx[x]=0;
M1[x]=0;
for (ll i=fst[x];i;i=nxt[i])
if (to[i]!=fa[x]&&fl[to[i]]==0)
{
fa[to[i]]=x;
Dfs(to[i]);
Mx[x]=max(Mx[x],max(Mx[to[i]],M1[x]+M1[to[i]]+len[i]));
M1[x]=max(M1[x],M1[to[i]]+len[i]);
}
}
struct T
{
ll l,r,a;
}nd[N*8],now;
T operator+(T a,T b)
{
return (T){max(a.l,b.l),max(a.r,b.r),max(max(a.a,b.a),a.l+b.r)};
}
void build(ll k,ll l,ll r)
{
if (l==r)
{
nd[k]=(T){vl[l],vr[l],0};
return;
}
ll mid=l+r>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
nd[k]=nd[k<<1]+nd[k<<1|1];
}
void qry(ll k,ll l,ll r,ll x,ll y)
{
if (x<=l&&r<=y)
{
if (now.a==-1) now=nd[k];
else now=now+nd[k];
return;
}
ll mid=l+r>>1;
if (x<=mid) qry(k<<1,l,mid,x,y);
if (y>mid) qry(k<<1|1,mid+1,r,x,y);
}
int main()
{
scanf("%lld",&n);
for (ll i=1;i<=n;i++)
{
scanf("%lld%lld%lld",&x,&y,&z);
link(x,y,z);
}
dfs(1);
for (;flag!=flag1;flag=fa[flag])
fl[a[++m]=flag]=1,b[m]=dep[flag]-dep[fa[flag]];
fl[a[++m]=flag1]=1;b[m]=flag2;
for (ll i=1;i<=m;i++)
fa[a[i]]=0,Dfs(a[i]),ly=max(ly,Mx[a[i]]);
for (ll i=1;i<=m;i++)
a[i+m]=a[i],b[i+m]=b[i];
for (ll i=1;i<=2*m;i++)
{
d[i]=d[i-1]+b[i-1];
vl[i]=M1[a[i]]-d[i];
vr[i]=M1[a[i]]+d[i];
}
build(1,1,2*m);
Ans=100000000000000L;
for (ll i=1;i<=m;i++)
{
now=(T){0,0,-1};
qry(1,1,2*m,i,i+m-1);
Ans=min(Ans,max(now.a,ly));
}
printf("%lld.%d\n",Ans/2,Ans&1?5:0);
}