题意
给出一棵环套树,求树上任意一个点(可以在边上),使得所有点到该点的最短路的最大值最小。
n≤105
n
≤
10
5
分析
如果这是一棵树的话,答案显然就是树的直径/2。
现在变成了环套树,考虑最优点,那么一定存在两个点使得他们到最优点的距离相等且都是最远的。
分两种情况讨论,一种是这三个点所在的链不经过环,这样的情况可以通过dp求出。
另一种是这三个点所在的链的一部分在环上,那么一定存在一条环上的边满足当我们把这条边去掉后答案不变,且这三个点组成的链是新树上的最长链。
设环的长度为len,我们先把环倍长,预处理前缀和,那么现在要求的就是所有长度为len的区间最大的
s[i]+d[i]−s[j]+d[j]
s
[
i
]
+
d
[
i
]
−
s
[
j
]
+
d
[
j
]
。
由于不能自己和自己配对,所以我们要记录最大值和次大值。
用堆来维护即可。
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>
#define mp(x,y) std::make_pair(x,y)
typedef long long LL;
typedef std::pair<LL,int> pi;
const int N=100005;
const LL inf=(LL)1e16;
int n,cnt,last[N],a[N*2],tot;
LL ans,s[N*2],f[N];
bool vis[N],ins[N];
struct edge{int to,next,w;}e[N*2];
struct Queue
{
std::priority_queue<pi> a,b;
void push(pi x)
{
a.push(x);
}
void pop()
{
while (!b.empty()&&a.top()==b.top()) a.pop(),b.pop();
a.pop();
}
pi top()
{
while (!b.empty()&&a.top()==b.top()) a.pop(),b.pop();
return a.top();
}
void del(pi x)
{
b.push(x);
}
}que1,que2;
void addedge(int u,int v,int w)
{
e[++cnt].to=v;e[cnt].w=w;e[cnt].next=last[u];last[u]=cnt;
e[++cnt].to=u;e[cnt].w=w;e[cnt].next=last[v];last[v]=cnt;
}
int find(int x,int fa)
{
ins[x]=1;
for (int i=last[x];i;i=e[i].next)
{
if (e[i].to==fa) continue;
if (ins[e[i].to]) {a[++tot]=x,s[tot]=e[i].w;return e[i].to;}
int y=find(e[i].to,x);
if (y) {a[++tot]=x;s[tot]=e[i].w;return y==x?0:y;}
}
ins[x]=0;
return 0;
}
void dp(int x,int fa)
{
LL mx1=0,mx2=0;
for (int i=last[x];i;i=e[i].next)
{
if (e[i].to==fa||vis[e[i].to]) continue;
dp(e[i].to,x);
LL w=f[e[i].to]+e[i].w;
if (w>mx1) mx2=mx1,mx1=w;
else if (w>mx2) mx2=w;
}
f[x]=mx1;ans=std::max(ans,mx1+mx2);
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
int x,y,z;scanf("%d%d%d",&x,&y,&z);
addedge(x,y,z);
}
find(1,0);
std::reverse(a+1,a+tot+1);
std::reverse(s+1,s+tot+1);
for (int i=1;i<=tot;i++) a[i+tot]=a[i],s[i+tot]=s[i];
for (int i=1;i<=tot*2;i++) s[i]+=s[i-1];
for (int i=tot*2;i>=1;i--) s[i]=s[i-1];
memset(vis,0,sizeof(vis));
for (int i=1;i<=tot;i++) vis[a[i]]=1;
for (int i=1;i<=tot;i++) dp(a[i],0);
for (int i=1;i<=tot;i++) que1.push(mp(f[a[i]]+s[i],a[i])),que2.push(mp(f[a[i]]-s[i],a[i]));
LL mn=inf;
for (int i=tot+1;i<=tot*2;i++)
{
LL w=0;
que1.del(mp(f[a[i-tot]]+s[i-tot],a[i-tot]));
que2.del(mp(f[a[i-tot]]-s[i-tot],a[i-tot]));
que1.push(mp(f[a[i]]+s[i],a[i]));
que2.push(mp(f[a[i]]-s[i],a[i]));
pi x1,x2,y1,y2;
x1=que1.top();que1.pop();x2=que1.top();que1.push(x1);
y1=que2.top();que2.pop();y2=que2.top();que2.push(y1);
if (x1.second==y1.second) w=std::max(x1.first+y2.first,x2.first+y1.first);
else w=x1.first+y1.first;
mn=std::min(mn,w);
}
printf("%.1lf",(double)std::max(ans,mn)/2);
return 0;
}