先二分答案 (mid),使得 $frac{val}{tot} geqslant mid $,移项得:
[large val - tot imes mid geqslant 0
]
判定对每条边的边权都减去 (mid) 后,是否存在一条边权和大于零的路径即可。
考虑树形 (DP),设 (f_{x,i}) 为以 (x) 为根的子树内,从 (x) 向下延伸 (i) 条边所形成的路径边权和的最大值,直接 (DP) 复杂度是 (O(n^2)) 的,无法接受。
发现状态是和深度有关,所以考虑用长链剖分来优化,每次转移时,先从重儿子继承过来,然后再将轻儿子合并,合并轻儿子时扫一遍轻儿子所在的链即可。因为每个轻儿子都是其所在链的顶端,所以每个点都只会被扫一次,复杂度就有保证了。
因为有边数的限制,所以合并时用线段树来维护。长链剖分后进行 (dfs),优先遍历重儿子,求出 (dfs) 序。对于 (DP) 状态 (f_{x,i}),将其用 (dfn_x + i) 在线段树上表示,这样每个状态都有一个对应的表示,转移时也便于合并,链上的信息为一个连续的区间,重儿子能直接转移到当前节点。
#include<bits/stdc++.h>
#define maxn 200010
#define maxm 800010
#define inf 2000000000000000
#define ls (cur<<1)
#define rs (cur<<1|1)
#define mid ((l+r)>>1)
using namespace std;
template<typename T> inline void read(T &x)
{
x=0;char c=getchar();bool flag=false;
while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
if(flag)x=-x;
}
int n,L,R,cnt,root=1;
double now,ans,l,r;
int d[maxn],dep[maxn],len[maxn],son[maxn],dfn[maxn];
double val[maxn],dis[maxn],t[maxn],mx[maxm];
struct edge
{
int to,nxt;
double v;
}e[maxn];
int head[maxn],edge_cnt;
void add(int from,int to,double val)
{
e[++edge_cnt]=(edge){to,head[from],val};
head[from]=edge_cnt,r=max(r,val);
}
void modify(int l,int r,int pos,double v,int cur)
{
if(l==r)
{
mx[cur]=max(mx[cur],v);
return;
}
if(pos<=mid) modify(l,mid,pos,v,ls);
else modify(mid+1,r,pos,v,rs);
mx[cur]=max(mx[ls],mx[rs]);
}
double query(int L,int R,int l,int r,int cur)
{
if(L>R) return -inf;
if(L<=l&&R>=r) return mx[cur];
double v=-inf;
if(L<=mid) v=max(v,query(L,R,l,mid,ls));
if(R>mid) v=max(v,query(L,R,mid+1,r,rs));
return v;
}
void clear(int l,int r,int cur)
{
mx[cur]=-inf;
if(l==r) return;
clear(l,mid,ls),clear(mid+1,r,rs);
}
void dfs_son(int x,int fa)
{
d[x]=dep[x]=d[fa]+1;
for(int i=head[x];i;i=e[i].nxt)
{
int y=e[i].to;
if(y==fa) continue;
dfs_son(y,x),dep[x]=max(dep[x],dep[y]);
if(dep[y]>dep[son[x]]) son[x]=y,val[son[x]]=e[i].v;
}
len[x]=dep[x]-d[x];
}
void dfs_dfn(int x)
{
dfn[x]=++cnt;
if(son[x]) dfs_dfn(son[x]);
for(int i=head[x];i;i=e[i].nxt)
{
int y=e[i].to;
if(dfn[y]) continue;
dfs_dfn(y);
}
}
void dp(int x,int fa)
{
modify(1,n,dfn[x],dis[x],root);
if(son[x]) dis[son[x]]=dis[x]+val[son[x]]-now,dp(son[x],x);
for(int i=head[x];i;i=e[i].nxt)
{
int y=e[i].to;
if(y==fa||y==son[x]) continue;
dis[y]=dis[x]+e[i].v-now,dp(y,x);
for(int j=1;j<=len[y]+1;++j) t[j]=query(dfn[y]+j-1,dfn[y]+j-1,1,n,root);
for(int j=1;j<=min(len[y]+1,R);++j)
ans=max(ans,t[j]+query(dfn[x]+L-j,min(dfn[x]+R-j,dfn[x]+len[x]),1,n,root)-2*dis[x]);
for(int j=1;j<=len[y]+1;++j) modify(1,n,dfn[x]+j,t[j],root);
}
ans=max(ans,query(dfn[x]+L,min(dfn[x]+R,dfn[x]+len[x]),1,n,root)-dis[x]);
}
bool check(double m)
{
now=m,ans=-inf,clear(1,n,root),dp(1,0);
return ans>=0;
}
int main()
{
read(n),read(L),read(R);
for(int i=1;i<n;++i)
{
int x,y,v;
read(x),read(y),read(v);
add(x,y,v),add(y,x,v);
}
dfs_son(1,0),dfs_dfn(1);
for(int i=1;i<=35;++i)
{
double m=(l+r)/2;
if(check(m)) l=m;
else r=m;
}
printf("%.3lf",l);
return 0;
}