传送门
长链剖分好题。
题意简述:给一棵树,问边数在 [ L , R ] [L,R] [L,R]之间的路径权值和与边数之比的最大值。
思路:
用脚指头想都知道要01分数规划。
考虑怎么 c h e c k check check。
发现就是求在转化成真·边权之后有没有长度在 [ L , R ] [L,R] [L,R]之间的路径权值是大于0的。
然后可以设计状态 f i , j f_{i,j} fi,j表示 i i i开头长度为 j j j的路径最大值,这个可以用长链剖分优化转移。
然后考虑怎么把经过 i i i的两条路径拼起来更新答案,这个可以用线段树优化转移,然后做完了。
代码:
#include
#define fi first
#define se second
#define ri register int
using namespace std;
inline int read(){
int ans=0;
char ch=getchar();
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
return ans;
}
const double eps=1e-4,inf=1e18;
const int N=1e5+5;
int n,len[N],fa[N],hson[N],tot=0,mxdep[N],dep[N],pos[N],num[N],D,U;
typedef pair<int,double> pii;
vector<pii>e[N];
struct edge{int u,v,w;}G[N];
double ans,f[N];
struct segement_tree{
#define lc (p<<1)
#define rc (p<<1|1)
#define mid (l+r>>1)
double mx[N<<2];
inline void pushup(int p){mx[p]=max(mx[lc],mx[rc]);}
inline void build(int p,int l,int r){
mx[p]=-inf;
if(l==r){pos[l]=p;return;}
build(lc,l,mid),build(rc,mid+1,r);
}
inline void update(int p,int l,int r,int k,double v){
if(l==r){mx[p]=max(mx[p],v);return;}
k<=mid?update(lc,l,mid,k,v):update(rc,mid+1,r,k,v),pushup(p);
}
inline double query(int p,int l,int r,int ql,int qr){
if(ql>r||qr<l)return -inf;
if(ql<=l&&r<=qr)return mx[p];
if(qr<=mid)return query(lc,l,mid,ql,qr);
if(ql>mid)return query(rc,mid+1,r,ql,qr);
return max(query(lc,l,mid,ql,mid),query(rc,mid+1,r,mid+1,qr));
}
}T;
void dfs1(int p){
for(ri i=0,v;i<e[p].size();++i){
if((v=e[p][i].fi)==fa[p])continue;
fa[v]=p,dep[v]=mxdep[v]=dep[p]+1,dfs1(v),mxdep[p]=max(mxdep[p],mxdep[v]);
if(mxdep[p]==mxdep[v])hson[p]=v;
}
len[p]=mxdep[p]-dep[p];
}
void dfs2(int p){
num[p]=++tot;
if(!hson[p])return;
dfs2(hson[p]);
for(ri i=0,v;i<e[p].size();++i)if((v=e[p][i].fi)!=fa[p]&&v!=hson[p])dfs2(v);
}
void solve(int p,double dist){
T.update(1,1,n,num[p],dist);
for(ri i=0;i<e[p].size();++i)if(e[p][i].fi==hson[p]){solve(hson[p],dist+e[p][i].se);break;}
for(ri i=0,v;i<e[p].size();++i){
if((v=e[p][i].fi)==fa[p]||v==hson[p])continue;
solve(v,dist+e[p][i].se);
for(ri j=1;j<=mxdep[v]-dep[p];++j){
f[j]=T.mx[pos[num[v]+j-1]];
if(j<=U){
double tmp=T.query(1,1,n,max(1,num[p]+D-j),min(num[p]+U-j,num[p]+len[p]));
ans=max(ans,tmp+f[j]-2*dist);
}
}
for(ri j=1;j<=mxdep[v]-dep[p];++j)T.update(1,1,n,num[p]+j,f[j]);
}
ans=max(ans,T.query(1,1,n,num[p]+D,min(num[p]+U,num[p]+len[p]))-dist);
}
inline bool check(double tmp){
ans=-inf,T.build(1,1,n);
for(ri i=1;i<=n;++i)e[i].clear();
for(ri i=1,u,v;i<n;++i){
u=G[i].u,v=G[i].v;
double w=G[i].w-tmp;
e[u].push_back(pii(v,w)),e[v].push_back(pii(u,w));
}
return solve(1,0),ans>=-eps;
}
int main(){
n=read(),D=read(),U=read();
double L=inf,R=0;
for(ri i=1;i<n;++i){
G[i].u=read(),G[i].v=read(),G[i].w=read(),L=min(L,(double)G[i].w),R=max(R,(double)G[i].w);
e[G[i].u].push_back(pii(G[i].v,0)),e[G[i].v].push_back(pii(G[i].u,0));
}
dfs1(1),dfs2(1);
while(R-L>=eps){
double Mid=(L+R)/2;
if(check(Mid))L=Mid;
else R=Mid;
}
printf("%.3lf",L);
return 0;
}