题目描述就不说了。要题目的请往百度NOI吧。
经典的树的分治,首先,对于答案是分数形式的基本上要使用二分答案,这不是胡扯,详情请见胡伯涛的论文。
那么对于这个题,由于不好估计边分治复杂度(其实边分治是可以过的,好像比点分治要快),对于答案,化成如下形式sigma{e}-ans*s=0,对于一个可行的ans设为val,必然满足sigma{e}-val*s>=0,所以二分。
点分治时,将每个节点到根的路径的权值计算出来,同时记录走过了多少条边。然后按照在每个子树中按照路径走过的边的数目排序,二分答案后验证,合并子树时,第一颗子树在一个数组list中按序保存走过s条边的路径权值最大值,以后的子树中枚举每条路径,利用单调性每次从list中加入一个值用单调队列维护路径的合法性和最优性,在做完一颗子树后这个子树保存的路径与list数组保存的信息合并,作为下一次list使用。
复杂度分析:点分治O(nlogn),每个节点被访问logn+1次,排序O(nlogn)为上限,二分答案验证为O(nlogans),一共做logn次,所以为O(nlognlogans)
Code:(注:不要作为对拍程序,貌似实现有bug)
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
struct element
{
int key;
double val;
} que[100005],lis[2][100005];
const double oo=10000000;
const element ori={0,0};
int vis[100005],sta[100005],next[200005],link[200005],head[100005],sum[100005],f[100005],l[100005],r[100005],dis[100005],a[100005],b[100005],count[100005],w[200005],pre[200005],tot[2],hea=0,tai=0;
bool flag[100005];
int time=0,top=0,tail=0,now=0,e=1,up=0,dn=0,n=0;
double ans=0,limitup=0,limitdn=0,mid=0;
inline void add(int u,int v,int tmpw)
{
next[++e]=head[u];
head[u]=e;
link[e]=v;
w[e]=tmpw;
pre[next[e]]=e;
next[++e]=head[v];
head[v]=e;
link[e]=u;
w[e]=tmpw;
pre[next[e]]=e;
}
inline void update(double &a,double b)
{
if (a<b) a=b;
}
inline int cal(int s)
{
++time;
f[s]=0;
top=0;
vis[s]=time;
sta[tail=1]=s;
int ne=0,y=0,x=0,i=0;
while (top<tail)
{
x=sta[++top];
for (ne=head[x],y=link[ne];ne;ne=next[ne],y=link[ne])
if (vis[y]!=time)
{
vis[y]=time;
sta[++tail]=y;
f[y]=x;
}
sum[x]=0;
flag[x]=1;
}
if (tail==1) return s;
for (i=tail,x=sta[i];i>=1;i--,x=sta[i])
{
sum[x]++;
sum[f[x]]+=sum[x];
if (sum[x]<=tail/2) flag[x]=0;
if (sum[x]>tail/2) flag[f[x]]=0;
if (flag[x]) return x;
}
}
void print(int s)
{
for (;s;s=f[s])
printf("%d ",s);
printf("\n");
}
void dfs(int s)
{
vis[s]=time;
int ne=0,x=0;
l[s]=r[s]=++now;
a[now]=dis[s];
b[now]=count[s];
for (ne=head[s],x=link[ne];ne;ne=next[ne],x=link[ne])
if (vis[x]!=time)
{
f[x]=s;
dis[x]=dis[s]+w[ne];
count[x]=count[s]+1;
if (dn<=count[x] && count[x]<=up) update(ans,(double)(dis[x])/count[x]);
dfs(x);
r[s]=r[x];
}
}
inline void swap(int &a,int &b)
{
int tmp=a;
a=b;
b=tmp;
}
inline void qs(int h,int g)
{
int l=h,k=g,mid=b[(l+k)/2];
while (l<=k)
{
while (b[l]<mid) l++;
while (b[k]>mid) k--;
if (l<=k)
{
swap(b[l],b[k]);
swap(a[l],a[k]);
l++;
k--;
}
}
if (l<g) qs(l,g);
if (h<k) qs(h,k);
}
inline bool com(int st)
{
return (dn<=st && st<=up);
}
bool check(double mid,int s)
{
int ne=head[s],x=link[ne],i=0,j=0,now=0,oth=1;
double tmpw=0;
tot[0]=tot[1]=hea=tai=0;
for (i=l[x];i<=r[x];i++)
{
if (b[i]==b[i-1]) update(lis[now][tot[now]].val,a[i]-b[i]*mid);
else
{
lis[now][++tot[now]].val=a[i]-b[i]*mid;
lis[now][tot[now]].key=b[i];
}
}
for (ne=next[ne],x=link[ne];ne;ne=next[ne],x=link[ne])
{
hea=tai=0;
j=tot[now];
for (i=l[x];i<=r[x];i++)
{
tmpw=a[i]-b[i]*mid;
for (;!com(que[hea].key+b[i]) && hea<=tai;hea++);
for (;lis[now][j].key+b[i]>up && j>0;j--);
for (;com(lis[now][j].key+b[i]) && j>0;j--)
{
for (;lis[now][j].val>que[tai].val && hea<=tai;tai--);
que[++tai]=lis[now][j];
}
if (hea<=tai && que[hea].val+tmpw>-(1e-5) && com(que[hea].key+b[i])) return 1;
}
oth=now;
now=1-now;
tot[now]=0;
i=l[x];j=1;
lis[oth][tot[oth]+1].key=n+1;
while (i<=r[x] || j<=tot[oth])
{
for (;i<=r[x] && lis[now][tot[now]].key==b[i];i++)
update(lis[now][tot[now]].val,a[i]-b[i]*mid);
for (;j<=tot[oth] && lis[now][tot[now]].key==lis[oth][j].key;j++)
update(lis[now][tot[now]].val,lis[oth][j].val);
if (i<=r[x])
if (b[i]<=lis[oth][j].key)
lis[now][++tot[now]].key=b[i],
lis[now][tot[now]].val=a[i]-b[i]*mid,i++;
else
lis[now][++tot[now]]=lis[oth][j],j++;
else
if (j<=tot[oth])
lis[now][++tot[now]]=lis[oth][j],j++;
}
}
return 0;
}
void getans(int s)
{
if (tail<dn) return;
++time;
now=0;
dis[s]=0;count[s]=0;
f[s]=0;
limitdn=0;
dfs(s);
limitup=1e6;
int ne=0,x=0,me=0;
for (ne=head[s],x=link[ne];ne;ne=next[ne],x=link[ne])
qs(l[x],r[x]);
while (limitdn+1e-5<limitup)
{
mid=(limitup+limitdn)/2;
if (check(mid,s))
limitdn=mid;
else
limitup=mid;
}
update(ans,limitdn);
for (ne=head[s],x=link[ne],me=ne^1;ne;ne=next[ne],x=link[ne],me=ne^1)
{
if (head[x]==me)
{
head[x]=next[me];
pre[next[me]]=0;
}
else
{
next[pre[me]]=next[me];
pre[next[me]]=pre[me];
}
pre[me]=0;next[me]=0;link[me]=0;w[me]=0;
getans(cal(x));
}
}
int main()
{
freopen("rebuild.in","r",stdin);
freopen("rebuild.out","w",stdout);
scanf("%d%d%d",&n,&dn,&up);
int i=0,u=0,v=0,tmpw=0;
for (i=1;i<n;i++)
{
scanf("%d%d%d",&u,&v,&tmpw);
add(u,v,tmpw);
}
ans=-oo;
getans(cal(1));
printf("%.3f",ans);
return 0;
}