[WC2010]重建计划 题解
Problem
给定一棵树,边有边权,要求找到一条长度在([L,R])之间的链,使得链的总价值和除以链长最大
Solution
显然,这个式子的形式让人想到了01分数规划。于是根据01分数规划的套路,先二分一个答案
考虑如何判断,现在等于把所有边都减去了一个(mid),要看有没有一条价值大于0的长度介于([L,R])的链
是不是感觉点分治呼之欲出。的确,到了这里就是一个点分治的经典例题了。但是这不是这篇题解的重点
显然DP也可做,记(f_{u,j})为在(u)子树中以(u)为端点的一条长度为(j)的链的最大价值,这个DP转移比较简单,但是复杂度是(O(n^2))的
我们发现这个DP的第二维状态与深度有关,故可以用长链剖分优化,统计答案时也可以用线段树优化,于是复杂度优化到了(O(nlog^2n))
Code
#include<bits/stdc++.h>
#define inf 1e8
#define DB double
#define eps 1e-3
using namespace std;
int n,l,r,cnt,tim;
DB ans,res,f[100005],g[100005];
int head[100005],w[200005],to[200005],Next[200005];
int dfn[100005],son[100005],dep[100005],sonw[100005];
struct Segment_Tree{
DB seg[400005];
void clear(){
memset(seg,0xc2,sizeof seg);
}
void change(int k,int l,int r,int pos,DB val){
seg[k]=max(seg[k],val);
if(l==r)
return;
int mid=l+r>>1;
if(pos<=mid)
change(k<<1 ,l,mid ,pos,val);
else
change(k<<1|1,mid+1,r,pos,val);
return;
}
DB query(int k,int l,int r,int wl,int wr){
if(wl> r||l> wr)
return -inf;
if(wl<=l&&r<=wr)
return seg[k];
DB res=-inf;
int mid=l+r>>1;
res=max(res,query(k<<1 ,l,mid ,wl,wr));
res=max(res,query(k<<1|1,mid+1,r,wl,wr));
return res;
}
}T;
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=(x<<1)+(x<<3)+ch-'0';
ch=getchar();
}
return x*f;
}
inline void add(int u,int v,int p){
w[++cnt]=p;to[cnt]=v;Next[cnt]=head[u];head[u]=cnt;
}
void dfs(int u,int fa){
dep[u]=1;
for(register int i=head[u];i;i=Next[i]){
int v=to[i];
if(v!=fa){
dfs(v,u);
dep[u]=max(dep[u],dep[v]+1);
if(dep[v]>dep[son[u]]){
son[u]=v;
sonw[u]=w[i];
}
}
}
return;
}
void DP(int u,int fa,DB x){
if(!dfn[u])
dfn[u]=++tim;
f[dfn[u]]=0;
g[dfn[u]]=0;
if(son[u]){
DP(son[u],u,x);
f[dfn[u]]=x-g[dfn[u]+1]-sonw[u];
g[dfn[u]]=g[dfn[u]+1]+sonw[u]-x;
}
T.change(1,1,n,dfn[u],f[dfn[u]]);
for(register int i=head[u];i;i=Next[i]){
int v=to[i];
if(v==fa||v==son[u])
continue;
DP(v,u,x);
for(register int j=1;j<=dep[v];++j){
if(l<=dep[u]+j-1){
double now=T.query(1,1,n,dfn[u]+max(1,l-j),dfn[u]+min(r-j,dep[u]-1));
res=max(res,w[i]-x+f[dfn[v]+j-1]+g[dfn[v]]+g[dfn[u]]+now);
}
}
for(register int j=1;j<=dep[v];++j){
if(w[i]-x+f[dfn[v]+j-1]+g[dfn[v]]>g[dfn[u]]+f[dfn[u]+j]){
f[dfn[u]+j]=w[i]-x+f[dfn[v]+j-1]+g[dfn[v]]-g[dfn[u]];
T.change(1,1,n,dfn[u]+j,f[dfn[u]+j]);
}
}
}
if(dep[u]-1>=l)
res=max(res,g[dfn[u]]+T.query(1,1,n,dfn[u]+l,dfn[u]+min(r,dep[u]-1)));
return;
}
int check(DB x){
res=-inf;
T.clear();
DP(1,0,x);
return res>=0;
}
int main(){
n=read();l=read();r=read();
for(register int i=2;i<=n;++i){
int u=read(),v=read();
int p=read();
add(u,v,p);add(v,u,p);
}
dfs(1,0);
DB L=0,R=1e6,ans=0;
while(R-L>=eps/10){
DB mid=(L+R)/2;
if(check(mid)){
ans=mid;
L=mid;
}
else
R=mid;
}
printf("%0.3lf
",ans);
return 0;
}