卧薪尝胆,厚积薄发。
WC2010 重建计划
Date: Thu Dec 13 16:26:19 CST 2018 In Category: NoCategory

Description:

在一棵树上求一个长度在 $[L,R]$ 之间的平均值最大的路径。
$1\leqslant n\leqslant 10^5$

Solution:

和CF150E几乎是一样的,先套一个01分数规划,然后点分治 $+$ 单调队列就行了。

Code:


#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<queue>
#include<cctype>
#include<cstring>
using namespace std;
inline int rd()
{
register int res = 0,f = 1;
register char c = getchar();
while(!isdigit(c))
{
if(c == '-')f = -1;
c = getchar();
}
while(isdigit(c))
{
res = (res << 1) + (res << 3) + c - '0';
c = getchar();
}
return res * f;
}
int n,l,r;
#define MAXN 100010
struct edge
{
int to,nxt;
double v;
}e[MAXN << 1];
int edgenum = 0;
int lin[MAXN] = {0};
inline void add(int a,int b,double c)
{
e[++edgenum] = (edge){b,lin[a],c};lin[a] = edgenum;
e[++edgenum] = (edge){a,lin[b],c};lin[b] = edgenum;
return;
}
int sum,root,siz[MAXN],d[MAXN];
bool vis[MAXN];
void getroot(int k,int fa)
{
siz[k] = 1;d[k] = 0;
for(register int i = lin[k];i != 0;i = e[i].nxt)
{
if(vis[e[i].to] || e[i].to == fa)continue;
getroot(e[i].to,k);
siz[k] += siz[e[i].to];
d[k] = max(d[k],siz[e[i].to]);
}
d[k] = max(d[k],sum - siz[k]);
if(d[k] < d[root])root = k;
return;
}
vector<int> v[MAXN];
bool cmp(int a,int b){return siz[a] < siz[b];}
int rt;
void divide(int k)
{
vis[k] = true;
for(register int i = lin[k];i != 0;i = e[i].nxt)
{
if(vis[e[i].to])continue;
root = 0;sum = siz[e[i].to];
getroot(e[i].to,0);
v[k].push_back(root);
}
getroot(k,0);
sort(v[k].begin(),v[k].end(),cmp);
for(register vector<int>::iterator it = v[k].begin();it != v[k].end();++it)
{
divide(*it);
}
vis[k] = false;
return;
}
double mx = 0;
double t[MAXN];
double s[MAXN];
int depth = 0;
void dfs(int k,int fa,int dep,double val)
{
depth = max(depth,dep);
s[dep] = max(s[dep],val);
for(register int i = lin[k];i != 0;i = e[i].nxt)
{
if(!vis[e[i].to] && e[i].to != fa)
{
dfs(e[i].to,k,dep + 1,val + e[i].v);
}
}
return;
}
int q[MAXN],head,tail;
#define NEG -10000000000
inline void calc(int k)
{
t[0] = 0;
register int maxdep = 0;
for(register int i = lin[k];i != 0;i = e[i].nxt)
{
if(vis[e[i].to])continue;
depth = 0;
dfs(e[i].to,0,1,e[i].v);
head = 0;tail = -1;
depth = min(depth,r);
for(register int i = max(l - depth,0);i < r - depth && i <= maxdep;++i)
{
while(head <= tail && t[i] >= t[q[tail]])--tail;
q[++tail] = i;
}
for(register int i = depth;i >= 1;--i)
{
while(head <= tail && q[head] < l - i)++head;
while(head <= tail && t[r - i] >= t[q[tail]])--tail;
q[++tail] = r - i;
if(head <= tail)mx = max(mx,t[q[head]] + s[i]);
}
for(register int i = 1;i <= depth;++i)t[i] = max(t[i],s[i]);
maxdep = max(maxdep,depth);
for(register int i = 1;i <= depth;++i)s[i] = NEG;
}
for(register int i = 1;i <= maxdep;++i)t[i] = NEG;
return;
}
void work(int k)
{
vis[k] = true;
calc(k);
for(register vector<int>::iterator it = v[k].begin();it != v[k].end();++it)
{
work(*it);
}
vis[k] = false;
return;
}
inline bool check(double v)
{
mx = NEG;
for(register int i = 1;i <= edgenum;++i)e[i].v -= v;
work(rt);
for(register int i = 1;i <= edgenum;++i)e[i].v += v;
return (mx >= 0);
}
#define INF 0x3f3f3f3f
int main()
{
for(int i = 0;i < MAXN;++i)t[i] = s[i] = NEG;
scanf("%d%d%d",&n,&l,&r);
register int a,b;
register double c;
for(register int i = 1;i < n;++i)
{
a = rd();b = rd();c = rd();
add(a,b,c);
}
sum = n;root = 0;d[0] = INF;
getroot(1,0);
rt = root;
divide(root);
register double l = 0,r = 1000000,mid;
for(register int i = 1;i <= 40;++i)
{
mid = (l + r) / 2;
if(check(mid))l = mid;
else r = mid;
}
printf("%.3lf\n",l);
return 0;
}
Copyright © 2020 wjh15101051
ღゝ◡╹)ノ♡