传送门
似乎这题有很多种做法。
我的做法是, 先二分答案,然后再分治,这样,如果一开始就找到了路,就能很快返回。然而点分时找重心的常数比较大,我又是每次重新dfs,而不是再次利用前面的结果,然后就跑得很慢。
分治时,我是将每课子树,每个(不带权的)深度中取出(带权深度)最大的一个,组成一个数组a,先求解,把前面的结果组成一个单调队列,用双指针扫,再和前面的暴力合并,处理时我按子树深度排了个序,从小到大处理,这样,每次合并时,操作次数为所有子树的深度和,然后所有子树的深度和<=所有子树的大小=
O(n)
,这样,每次点分的复杂度就是
O(nlogn)
假如不按深度从小到大处理,而是任意顺序,那么对于一条链,链的一端是一朵菊花,处理分治中心为菊花花心时就会爆炸。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cctype>
using namespace std;
typedef long long ll;
typedef double db;
const int N=100005;
const db eps=1e-4;
inline void up(db&a,db b){
if(a<b)a=b;
}
inline void up(int&a,int b){
if(a<b)a=b;
}
inline int min(int a,int b){
return a>b?b:a;
}
int n,u,v,w,i,L,U;
db l,r,m;
struct tree{
struct edge{
int to,next,w;
db c;
}e[N<<1];
int xb,h[N],rt,sum,sz[N],f[N],w,dd,z,q[N],tt,ww;
db a[N],m[N],len[N];
bool b[N];
struct node{
int v,l,r;
bool operator<(const node&x)const{
return v<x.v;
}
}d[N];
inline void addedge(int u,int v,int w){
e[++xb]=(edge){v,h[u],w};
h[u]=xb;
e[++xb]=(edge){u,h[v],w};
h[v]=xb;
}
void dfs(int x,int fa){
f[x]=sz[x]=1;
for(int i=h[x];i;i=e[i].next)
if(e[i].to!=fa && !b[e[i].to])dfs(e[i].to,x),sz[x]+=sz[e[i].to],up(f[x],sz[e[i].to]);
up(f[x],sum-sz[x]);
if(f[rt]>f[x])rt=x;
}
void getdep(int x,int fa,int dep){
if(dep>dd)dd=dep;
if(len[x]>a[z+dep])a[z+dep]=len[x];
for(int i=h[x];i;i=e[i].next)
if(e[i].to!=fa && !b[e[i].to])len[e[i].to]=len[x]+e[i].c,getdep(e[i].to,x,dep+1);
}
bool work(int x){
int i,j;
for(i=0;i<=sum;++i)m[i]=-(1ll<<50),a[i]=-(1ll<<50);
w=z=0;
for(i=h[x];i;i=e[i].next)
if(!b[e[i].to]){
len[e[i].to]=e[i].c;
dd=0;
getdep(e[i].to,x,1);
d[++w].v=dd;
d[w].l=z+1;
d[w].r=z+=dd;
for(j=d[w].l+L-1;j<=z;++j)if(a[j]>0)return 1;
}
sort(d+1,d+w+1);
for(j=d[1].l;j<=d[1].r;++j)m[j-d[1].l+1]=a[j];
for(i=2;i<=w;++i){
tt=1;
ww=0;
for(j=min(d[i-1].r-d[i-1].l+1,U-1);j>=L-1;--j){
while(ww && m[j]>m[q[ww]])--ww;
if(!ww || m[j]>m[q[ww]])q[++ww]=j;
}
for(j=d[i].l;j<=d[i].r;++j){
if(j-d[i].l+1+q[tt]>U)++tt;
if(tt<=ww && m[q[tt]]+a[j]>0)return 1;
while(tt<=ww && m[L-(j-d[i].l+1)-1]>m[q[ww]])--ww;
if(tt>ww || m[L-(j-d[i].l+1)-1]>m[q[ww]])q[++ww]=L-(j-d[i].l+1)-1;
}
for(j=d[i].l;j<=d[i].r;++j)up(m[j-d[i].l+1],a[j]);
}
return 0;
}
bool solve(int x){
b[x]=1;
for(int i=h[x];i;i=e[i].next)if(sz[e[i].to]>sz[x])sz[e[i].to]=sum-sz[x];
if(work(x))return 1;
for(int i=h[x];i;i=e[i].next)
if(!b[e[i].to]){
sum=sz[e[i].to];
rt=0;
dfs(e[i].to,x);
if(solve(rt))return 1;
}
return 0;
}
}t;
inline int getint(){
int x=0;
char c=getchar();
while(!isdigit(c))c=getchar();
for(;isdigit(c);c=getchar())x=x*10+c-48;
return x;
}
int main(){
scanf("%d%d%d",&n,&L,&U);
for(i=1;i<n;++i){
scanf("%d%d%d",&u,&v,&w);
t.addedge(u,v,w);
if(w>r)r=w;
}
t.f[0]=1<<30;
l=0;
while(r-l>eps){
m=(l+r)/2;
memset(t.b,0,sizeof t.b);
t.sum=n;
for(i=1;i<=t.xb;++i)t.e[i].c=t.e[i].w-m;
t.dfs(1,t.rt=0);
if(t.solve(t.rt))l=m;
else r=m;
}
printf("%.3f\n",l);
return 0;
}