感觉仿佛所有统计路径的题都可以把锅甩给点分治???
由于要求平均值最大,我们每二分一个答案ave,就去检查是否存在一条路径满足其新路径长度(d(u,v)-ave)的和大于等于0,并且路径的长度在[L,R]之间,检查的时候技巧很多,可以用单调栈来维护当前各深度边权最大值。
同时,要善于利用时间戳来避免一切memset。并且由于答案是三位小数,因此我们可以控制当r-l<=1e-4时跳出即可。
/**************************************************************
Problem: 1758
User: RicardoWang
Language: C++
Result: Accepted
Time:23284 ms
Memory:13488 kb
****************************************************************/
#include<cstdlib>
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
#define maxn 100005
#define oo 999999999
struct edge
{
int to,d,next; bool ban;
}e[maxn*2];
int n,edge_ct,head[maxn],sz[maxn],L,R;
void add(int x,int y,int de)
{
e[++edge_ct]=(edge){y,de,head[x],false}; head[x]=edge_ct;
return ;
}
void _read(int &x)
{
char ch=getchar(); x=0;while(ch<'0'||ch>'9')ch=getchar(); while(ch>='0' && ch<='9'){x=x*10+ch-'0'; ch=getchar();}return ;
}
int MMD;
void Init()
{
_read(n);edge_ct=0;
_read(L); _read(R);
int x,y,z;MMD=-1;
for(int i=1;i<n;i++)
{
_read(x);_read(y); _read(z);MMD=max(MMD,z);
add(x,y,z); add(y,x,z);
}
return ;
}
int maxd;
int maxl[maxn];
void Get_gc(int now,int fa,int size,int &gc)
{
bool flag=1;int j;
sz[now]=1;maxl[now]=0;
for(int id=head[now];id;id=e[id].next)
{
if(e[id].ban || e[id].to==fa)continue;
j=e[id].to;Get_gc(j,now,size,gc);
if(sz[j]>(size>>1))flag=false;
sz[now]+=sz[j];
maxd=max(maxd,maxl[now]+maxl[j]+1);maxl[now]=max(maxl[now],maxl[j]+1);
}
if(size-sz[now]>(size>>1))flag=false;
if(flag)gc=now;
return ;
}
double ans=-oo;
int _time,_MaxD;
double dp[maxn],dp1[maxn];
int T[maxn];
void DFS(int now,int fa,int dep,double sum,double ave)
{
_MaxD=max(_MaxD,dep);
sz[now]=1;
if(T[dep]<_time || (T[dep]==_time && dp1[dep]<sum))dp1[dep]=sum,T[dep]=_time;
for(int id=head[now];id;id=e[id].next)
{
if(e[id].to==fa || e[id].ban)continue;
DFS(e[id].to,now,dep+1,sum-ave+(double)e[id].d,ave);sz[now]+=sz[e[id].to];
}
return ;
}
int qu[maxn],front,rear;
bool Calc(int now,double ave)
{
for(int i=0;i<=R;i++)dp[i]=-oo,T[i]=0;
dp[0]=0;_time=0;
int w;;
for(int id=head[now];id;id=e[id].next)
{
if(e[id].ban)continue;
_time++;
_MaxD=0;
DFS(e[id].to,now,1,(double)e[id].d-ave,ave);
//w=min(R,_MaxD);
w=max(0,L-_MaxD);
front=rear=1;
for(int i=_MaxD;i;i--)
{
for(;w+i<=R;w++)
{
while(rear>front && dp[w]>dp[qu[rear-1]])rear--;
qu[rear++]=w;
}
while(rear>front && qu[front]+i<L)front++;
if(rear>front && dp[qu[front]]+dp1[i]>=0)return true;
}
for(int j=1;j<=_MaxD && j<=R;j++)if(T[j]==_time)
{
dp[j]=max(dp[j],dp1[j]);
}
}
return false;
}
void Tree_Devide(int now,int size)
{
int gc;
maxd=0;
Get_gc(now,0,size,gc);
if(maxd<L)return ;
double l=ans,r=MMD,mid;
while(r-l>1e-4)
{
mid=(l*9.0+r)/10.0;
if(Calc(gc,mid))
{
ans=mid; l=mid;
}
else
{
r=mid;
}
}
for(int id=head[gc];id;id=e[id].next)if(!e[id].ban)
{
e[id].ban=e[id+(id%2==0 ? -1:1)].ban=true;
Tree_Devide(e[id].to,sz[e[id].to]);
}
return ;
}
void work()
{
Tree_Devide(1,n);
printf("%.3lf\n",ans);
return;
}
int main()
{
//freopen("in.txt","r",stdin);
Init();
work();
return 0;
}