传送门
题意:给一棵nnn个点的基环树,找一个点(可以在边上),求所有节点到这个点的最大值的最小值。
n≤1e5n \leq1e5n≤1e5
先考虑一棵普通树的情况
显然是直径长度的一半
因为如果有个点大于直径长度的一半,显然可以找一个更长的链,所以这个长度可以覆盖所有点。而如果小于,不能覆盖直径的端点。
如果是基环树,发现仍然可以按普通树的形式覆盖所有点。也就是断掉环上的一条边后的最小直径。
非环边是不受影响的,分别跑一次直径记录下来。
对每个环上的点记录最大深度,套路性地断环为链,set瞎搞一下就出来了
和前面的最大直径取max输出
复杂度O(nlogn)O(nlogn)O(nlogn)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cctype>
#include <utility>
#include <set>
#define MAXN 100005
#define MAXM 200005
using namespace std;
typedef long long ll;
inline int read()
{int ans=0;char c=getchar();while (!isdigit(c)) c=getchar();while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();return ans;
}
struct edge{int u,v,w;}e[MAXM];
int head[MAXN],nxt[MAXM],cnt;
void addnode(int u,int v,int w)
{e[++cnt]=(edge){u,v,w};nxt[cnt]=head[u];head[u]=cnt;
}
bool vis[MAXN],isrt[MAXN];
int lop[MAXN],x[MAXN],tot,tmp;
ll dep[MAXM];
void dfs(int u,int f)
{vis[u]=true;for (int i=head[u];i;i=nxt[i])if (!vis[e[i].v]&&e[i].v!=lop[1]){dfs(e[i].v,u);if (isrt[e[i].v]&&e[i].v!=tmp) isrt[lop[++tot]=u]=true,x[tot]=e[i].w;}elseif (e[i].v!=f&&e[i].v!=lop[1])isrt[lop[++tot]=u]=true,x[tot]=e[i].w,tmp=e[i].v;vis[u]=false;
}
ll dis[MAXN]={-1};
int mx;
void getdis(int u,int f)
{if (dis[u]>dis[mx]) mx=u;for (int i=head[u];i;i=nxt[i])if (e[i].v!=f&&!isrt[e[i].v]){dis[e[i].v]=dis[u]+e[i].w;getdis(e[i].v,u);}
}
typedef pair<ll,int> pi;
multiset<pi> s1,s2;//+,-
inline ll calc(){return s1.rbegin()->second==s2.rbegin()->second? max((++s1.rbegin())->first+s2.rbegin()->first,s1.rbegin()->first+(++s2.rbegin())->first):s1.rbegin()->first+s2.rbegin()->first;}
ll sum[MAXM];
int main()
{int n=read();for (int i=1;i<=n;i++){int u,v,w;u=read(),v=read(),w=read();addnode(u,v,w);addnode(v,u,w);}dfs(1,0);ll ans0=0;for (int i=1;i<=tot;i++){isrt[lop[i]]=false;mx=0;dis[lop[i]]=mx=0;getdis(lop[i],0);dep[i]=dis[mx];dis[mx]=0;getdis(mx,0);ans0=max(ans0,dis[mx]);isrt[lop[i]]=true;}for (int i=2;i<=tot;i++) sum[i]=sum[i-1]+x[i];for (int i=tot+1;i<=2*tot;i++) sum[i]=sum[i-1]+x[i-tot],dep[i]=dep[i-tot];ll ans1=1e18;for (int i=1;i<=tot;i++) s1.insert(make_pair(dep[i]+sum[i],i)),s2.insert(make_pair(dep[i]-sum[i],i));ans1=min(ans1,calc());for (int i=tot+1;i<=2*tot-1;i++){s1.erase(s1.find(make_pair(dep[i-tot]+sum[i-tot],i-tot)));s2.erase(s2.find(make_pair(dep[i-tot]-sum[i-tot],i-tot)));s1.insert(make_pair(dep[i]+sum[i],i));s2.insert(make_pair(dep[i]-sum[i],i));ans1=min(ans1,calc());}ans1=max(ans0,ans1);printf("%lld.%d\n",ans1>>1,(ans1&1)? 5:0);return 0;
}