​传送门​


首先求一个最优比率的东西,我们二分答案,转化成判定是否存在一条合法路径使得边权和≥0.

然后这个东西我们点分治去做。每次计算过x的合法路径的最大值时,为了避免不合法,我们一个子树一个子树的做。

我们处理出g[i],表示目前这棵子树深度为i的点的最大距离,tmp[i]表示之前做过的子树深度为i的点的最大距离。

我们每次用g[i]去询问tmp,也就是要在tmp[l-i,r-i]中选一个最大值,我们发现这就是一个滑动的窗口,可以用单调队列来维护。

然后为了保证复杂度,我们要按子树深度(大小)从小到大来做。清零要手动清。

为了卡常,我们二分答案要在每次分治里面分,最小值直接从ans开始枚举,子树大小< L时就可以不做了


#include<bits/stdc++.h>
#define N 100050
#define inf 0x3fffffff
#define eps 1e-4
using namespace std;
int read(){
int cnt = 0; char ch = 0;
while(!isdigit(ch)) ch = getchar();
while(isdigit(ch)) cnt = cnt*10 + (ch-'0'), ch = getchar();
return cnt;
}
int first[N], nxt[N*2], to[N*2], w[N*2], tot;
void add(int x,int y,int z){
nxt[++tot] = first[x], first[x] = tot;
to[tot] = y, w[tot] = z;
}
int n,L,R,Siz,Maxdep;
int dep[N], siz[N], fa[N], Maxson[N];
int rt, sum, vis[N]; double ans, mid, g[N], tmp[N], dis[N];
struct Son{ int id, val;}son[N];
bool cmp(Son a,Son b){ return siz[a.id] < siz[b.id];}
void dfs(int u,int f){
siz[u] = 1;
for(int i=first[u];i;i=nxt[i]){
int t = to[i]; if(t==f || vis[t]) continue;
fa[t] = u, dep[t] = dep[u] + 1;
dfs(t,u); siz[u] += siz[t];
}
}
void getrt(int u){
Maxson[u] = 0;
for(int i=first[u];i;i=nxt[i]){
int t = to[i]; if(t==fa[u] || vis[t]) continue;
getrt(t); Maxson[u] = max(Maxson[u], siz[t]);
} Maxson[u] = max(Maxson[u], Siz - siz[u]);
if(Maxson[u] < Maxson[rt]) rt = u;
}
void getdis(int u){
g[dep[u]] = max(g[dep[u]], dis[u]);
Maxdep = max(Maxdep, dep[u]);
for(int i=first[u];i;i=nxt[i]){
int t = to[i]; if(vis[t] || t==fa[u]) continue;
dis[t] = dis[u] + w[i] - mid; getdis(t);
}
}
bool check(int x){
int Max = 0, flag = 0; tmp[0] = 0;
deque<pair<double,int> > q;
for(int d=1; d<=sum; d++){
int pos = son[d].id; if(vis[pos]) continue;
dis[pos] = son[d].val - mid;
Maxdep = 0; getdis(pos);
int now = L - Maxdep; now = max(now, 0);
for(int i=Maxdep; i>=1; i--){
while(now <= Max && now + i <= R){
while(!q.empty() && tmp[now] > q.back().first) q.pop_back();
q.push_back(make_pair(tmp[now], now)); now ++;
}
while(!q.empty() && q.front().second + i < L) q.pop_front();
if(!q.empty() && q.front().first + g[i] >= -eps){ flag = 1; break;}
}
for(int i=Maxdep; i>=1; i--){
tmp[i] = max(tmp[i], g[i]), g[i] = -inf;
} Max = max(Max, Maxdep);
if(flag) break;
}
for(int i=0;i<=Max;i++) tmp[i] = -inf;
return flag;
}
void Solve(int x){
vis[x] = 1; fa[x] = 0; dep[x] = 0; dfs(x,0);
if(siz[x] < L) return;
double l = ans, r = 1000000; sum = 0;
for(int i=first[x];i;i=nxt[i]){
int t = to[i]; if(vis[t]) continue;
son[++sum] = (Son){t, w[i]};
} sort(son+1, son+sum+1, cmp);
while((r-l) > eps){
mid = (l+r) / 2;
if(check(x)) l = mid;
else r = mid;
} ans = l;
for(int i=first[x];i;i=nxt[i]){
int t = to[i]; if(vis[t]) continue;
rt = 0, Siz = siz[t]; getrt(t); Solve(rt);
}
}
int main(){
n = read(), L = read(), R = read();
for(int i=1; i<n; i++){
int x = read(), y = read(), z = read();
add(x,y,z); add(y,x,z);
}
for(int i=0;i<=n;i++) g[i] = tmp[i] = -inf;
dfs(1,0); rt = 0, Maxson[rt] = inf, Siz = n;
getrt(1); Solve(rt); printf("%0.3lf",ans); return 0;
}