//被卡常了
#pragma GCC optimize("O2")
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
#define rep(i,j,k) for(i=j;i<=k;++i)
#define per(i,j,k) for(i=j;i>=k;--i)
#define sqr(x) ((x)*(x))
#define G getchar()
#define LL long long
#define pll pair<LL,LL>
#define mkp make_pair
#define X first
#define Y second
#define N 100005
#define NN 10000000
#define inf 100000000001.0
#define eps 0.000001
int n,MIN,MAX;
int he[N],ne[N<<1],to[N<<1],W[N<<1],tot;
int sz[N],mx[N],rt[N],rk[N],cnt,ln[N];
int q[N],inq[N],dep[N],md1,md0;double sum[N],Max0[N],Max[N];
//dep表示深度,sum[I]表示根到i的边权和
//Max0[i]表示已经搜过的子树中,dep为i的点的sum的最大值。md0表示其最大下标
//Max表示当前正在搜的子树中,dep为I的点的sum最大值。md1表示其最大下标
//inq表示是否在队列中,等于cnt表示在,否则表示不在
inline int read(){
int x=0;char ch=G;
while(x>57||ch<48)ch=G;
for(;ch<58&&ch>47;ch=G)x=x*10+ch-48;
return x;
}
inline void add(int x,int y,int z){
to[++tot]=y;W[tot]=z;ne[tot]=he[x];he[x]=tot;
}
void getrt(int x,int e){
int i,y;mx[x]=0;sz[x]=1;//mx记录该节点的最大子树大小,sz表示以自己为根的子树大小
for(i=he[x];i;i=ne[i])if(i!=e&&!rk[y=to[i]]){
getrt(y,i^1);mx[x]=max(mx[x],sz[y]);sz[x]+=sz[y];
}
if((mx[x]=max(mx[x],ln[cnt]-sz[x]))<mx[rt[cnt]])rt[cnt]=x;
}
inline int dcmp(double x){
if(fabs(x)<eps)return 0;
return x>0?1:-1;
}
inline bool BFS(int x,double ans){
int u,v,Ft=1,Rr=2,i,j;bool rtn=0;
//预处理Max
for(inq[q[1]=x]=cnt;Ft<Rr;){
u=q[Ft++];Max[dep[u]]=max(Max[dep[u]],sum[u]);
for(i=he[u];i;i=ne[i])if(rk[v=to[i]]>cnt&&inq[v]<cnt){
inq[q[Rr++]=v]=cnt;dep[v]=dep[u]+1;sum[v]=sum[u]+W[i]-ans;
}
}
md1=dep[q[Rr-1]];j=md0;Ft=Rr=1;
//MIN-I和MAX-I可看成一个滑动窗口,因此维护Max0的单调递减队列
rep(i,MIN-md0,md1){
while(Ft<Rr&&i+q[Ft]>MAX)Ft++;
while(j&&i+j>=MIN){
while(Ft<Rr&&dcmp(Max0[j]-Max0[q[Rr-1]])>=0)Rr--;
q[Rr++]=j--;
}
if(Ft<Rr&&dcmp(Max0[q[Ft]]+Max[i])>=0){
rtn=1;break;
}
}
md0=max(md0,md1);
rep(i,1,md1)Max0[i]=max(Max0[i],Max[i]);
return rtn;
}
inline bool check(double ans){
int i,j,x,y,rg;
rep(i,1,n)Max[i]=Max0[i]=-inf,inq[i]=0;
//随时保证Max和Max0的初始值为-inf。Max0遍历每个根时都盖掉,Max遍历每棵子树时都改掉。
rep(cnt,1,n){
if(ln[cnt]<=MIN)continue;
dep[x=rt[cnt]]=0;
rep(i,1,md0)Max0[i]=-inf;md0=0;
for(i=he[x];i;i=ne[i])if(rk[y=to[i]]>cnt){
rep(j,1,md1)Max[j]=-inf;md1=0;
sum[y]=W[i]-ans;dep[y]=1;
if(BFS(y,ans))return 1;
}
rg=min(MAX,md0);
rep(i,MIN,rg)if(dcmp(Max0[i])>=0)return 1;
}
return 0;
}
int main(){
freopen("r.in","r",stdin);
freopen("w.out","w",stdout);
//读入
int i,x,y,z,j,rr=1;double l,r,mid;
n=read();MIN=read();MAX=read();tot=1;
rep(i,2,n){
x=read();y=read();z=read();
rr=max(z,rr);add(x,y,z);add(y,x,z);
}
//提前把每棵树的重心都找出来,rt[i]表示第i个搜谁,rk[i]表示第i个什么时候搜
mx[n+1]=rt[cnt=1]=n+1;ln[1]=n;getrt(1,0);
rep(i,1,n){
rk[rt[i]]=i;
for(j=he[rt[i]];j;j=ne[j])if(!rk[y=to[j]]){
rt[++cnt]=n+1;ln[cnt]=sz[y];getrt(y,0);
}
}
//实数二分
for(l=1,r=rr;dcmp(r-l);){
mid=(l+r)/2;
if(check(mid))l=mid;
else r=mid;
}
printf("%.3lf\n",l);
return 0;
}
1758: [Wc2010]重建计划
最新推荐文章于 2021-03-01 22:16:19 发布