正题

题目链接:https://www.luogu.com.cn/problem/P4292


题目大意

给出\(n\)个点的一棵树,然后求长度在\([L,U]\)之间的一条路径的平均权值最大。


解题思路

先上二分\(0/1\)分数规划,然后变成求最长在\([L,U]\)之间的路径。

很经典的点分治问题,但是用线段树会\(T\),当然可以用单调队列但是我不会。

可以试下上长剖,线段树维护链上每个深度的最大值权值。然后枚举短的那条链的时候在长的那条上面线段树查询就好了。

时间复杂度\(O(n\log^2 n)\)


code

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1e5+10;
const double inf=1e18,eps=1e-6;
struct node{
int to,next;
double w;
}a[N<<1];
int n,L,U,tot,cnt,ls[N];
int dep[N],len[N],son[N],rt[N];
double f[N],nw[N],ans;
struct SegTree{
double w[N<<5];int ls[N<<5],rs[N<<5];
void Change(int &x,int L,int R,int pos,double val){
if(!x)x=++cnt,ls[x]=rs[x]=0,w[x]=-inf;
if(L==R){w[x]=max(val,w[x]);return;}
int mid=(L+R)>>1;
if(pos<=mid)Change(ls[x],L,mid,pos,val);
else Change(rs[x],mid+1,R,pos,val);
w[x]=max(w[ls[x]],w[rs[x]]);return;
}
double Ask(int x,int L,int R,int l,int r){
if(l<L)l=L;if(r>R)r=R;
if(!x||l>r)return -inf;
if(L==l&&R==r)return w[x];
int mid=(L+R)>>1;
if(r<=mid)return Ask(ls[x],L,mid,l,r);
if(l>mid)return Ask(rs[x],mid+1,R,l,r);
return max(Ask(ls[x],L,mid,l,mid),Ask(rs[x],mid+1,R,mid+1,r));
}
}T;
void addl(int x,int y,double w){
a[++tot].to=y;
a[tot].next=ls[x];
ls[x]=tot;a[tot].w=w;
return;
}
void dfs(int x,int fa){
dep[x]=dep[fa]+1;
for(int i=ls[x];i;i=a[i].next){
int y=a[i].to;
if(y==fa)continue;
dfs(y,x);
if(len[y]>len[son[x]])
son[x]=y,nw[x]=a[i].w;
}
len[x]=len[son[x]]+1;
return;
}
void solve(int x,int fa,int t,double k,double dis){
rt[x]=0;
if(son[x])solve(son[x],x,t,k,dis+nw[x]-k);
T.Change(rt[t],dep[t],dep[t]+len[t],dep[x],dis);
for(int i=ls[x];i;i=a[i].next){
int y=a[i].to;
if(y==son[x]||y==fa)continue;
solve(y,x,y,k,dis+a[i].w-k);
for(int j=dep[y];j<=dep[y]+len[y];j++){
f[j]=T.Ask(rt[y],dep[y],dep[y]+len[y],j,j);
ans=max(ans,f[j]+T.Ask(rt[t],dep[t],dep[t]+len[t],2*dep[x]+L-j,2*dep[x]+U-j)-2*dis);
}
for(int j=dep[y];j<=dep[y]+len[y];j++)
T.Change(rt[t],dep[t],dep[t]+len[t],j,f[j]);
}
ans=max(ans,T.Ask(rt[t],dep[t],dep[t]+len[t],dep[x]+L,dep[x]+U)-dis);
return;
}
bool check(double k){
ans=T.w[0]=-inf;cnt=0;
solve(1,1,1,k,0);
return ans>-eps;
}
int main()
{
scanf("%d%d%d",&n,&L,&U);
for(int i=1;i<n;i++){
int x,y,w;
scanf("%d%d%d",&x,&y,&w);
addl(x,y,w);addl(y,x,w);
}
len[0]=-1;dfs(1,1);
double l=0,r=1e6;
while(r-l>eps){
double mid=(l+r)/2.0;
if(check(mid))l=mid;
else r=mid;
}
check(1e6);
printf("%.3lf",(l+r)/2.0);
return 0;
}

P4292-[WC2010]重建计划【长链剖分,线段树,0/1分数规划】的更多相关文章

  1. BZOJ 3672[NOI2014]购票(树链剖分+线段树维护凸包+斜率优化) + BZOJ 2402 陶陶的难题II (树链剖分+线段树维护凸包+分数规划+斜率优化)

    前言 刚开始看着两道题感觉头皮发麻,后来看看题解,发现挺好理解,只是代码有点长. BZOJ 3672[NOI2014]购票 中文题面,题意略: BZOJ 3672[NOI2014]购票 设f(i)f( ...

  2. [WC2010]重建计划 长链剖分

    [WC2010]重建计划 LG传送门 又一道长链剖分好题. 这题写点分治的人应该比较多吧,但是我太菜了,只会长链剖分. 如果你还不会长链剖分的基本操作,可以看看我的长链剖分总结. 首先一看求平均值最大 ...

  3. [BZOJ2402]陶陶的难题II(树链剖分+线段树维护凸包+分数规划)

    陶陶的难题II 时间限制:40s      空间限制:128MB 题目描述 输入格式 第一行包含一个正整数N,表示树中结点的个数. 第二行包含N个正实数,第i个数表示xi (1<=xi<= ...

  4. BZOJ.1758.[WC2010]重建计划(分数规划 点分治 单调队列/长链剖分 线段树)

    题目链接 BZOJ 洛谷 点分治 单调队列: 二分答案,然后判断是否存在一条长度在\([L,R]\)的路径满足权值和非负.可以点分治. 对于(距当前根节点)深度为\(d\)的一条路径,可以用其它子树深 ...

  5. 「WC2010」重建计划(长链剖分/点分治)

    「WC2010」重建计划(长链剖分/点分治) 题目描述 有一棵大小为 \(n\) 的树,给定 \(L, R\) ,要求找到一条长度在 \([L, R]\) 的路径,并且路径上边权的平均值最大 \(1 ...

  6. 洛谷 P4292 - [WC2010]重建计划(长链剖分+线段树)

    题面传送门 我!竟!然!独!立!A!C!了!这!道!题!incredible! 首先看到这类最大化某个分式的题目,可以套路地想到分数规划,考虑二分答案 \(mid\) 并检验是否存在合法的 \(S\) ...

  7. BZOJ1758[Wc2010]重建计划——分数规划+长链剖分+线段树+二分答案+树形DP

    题目描述 输入 第一行包含一个正整数N,表示X国的城市个数. 第二行包含两个正整数L和U,表示政策要求的第一期重建方案中修建道路数的上下限 接下来的N-1行描述重建小组的原有方案,每行三个正整数Ai, ...

  8. 2019.01.21 bzoj1758: [Wc2010]重建计划(01分数规划+长链剖分+线段树)

    传送门 长链剖分好题. 题意简述:给一棵树,问边数在[L,R][L,R][L,R]之间的路径权值和与边数之比的最大值. 思路: 用脚指头想都知道要01分数规划. 考虑怎么checkcheckcheck ...

  9. [WC2010]重建计划(长链剖分+线段树+分数规划)

    看到平均值一眼分数规划,二分答案mid,边权变为w[i]-mid,看是否有长度在[L,R]的正权路径.设f[i][j]表示以i为根向下j步最长路径,用长链剖分可以优化到O(1),查询答案线段树即可,复 ...

随机推荐

  1. JS获取对象在内存中计算后的样式

    通过obj.style的方式只能取得"内联style"的值,对于<style></style>中的css属性值,则无能为力 . 我们可以用obj.curre ...

  2. java实用资料

    1.怎么构造一个线程安全的hashmap?用reentrantreadwritelock2.线程是怎么处理二个以上的对象同时处理一个全局变量 3.读文件为啥不用字符流 4.请求鉴定,各种错误码502- ...

  3. C# Monitor.Wait() 源码追踪 (转载)

    source: 释放对象上的锁并阻止当前线程,直到它重新获取该锁. 如果已用指定的超时时间间隔,则线程进入就绪队列. 可以在等待之前退出同步上下文的同步域,随后重新获取该域. [SecuritySaf ...

  4. Spring详解(八)------常用的连接池配置

    首先,我们准备Jdbc属性文件 jdbc.properties,用于保存连接数据库的信息,利于我们在配置文件中的使用 jdbc.driver=com.mysql.jdbc.Driver jdbc.ur ...

  5. Spring parent 属性

    Spring Framework Reference Documentation 6.7. Bean definition inheritance 注:本文中bean和definition意思等同 该 ...

  6. go协程调度

    目录 前言 1. 线程池的缺陷 2.Goroutine 调度器 3.调度策略 3.1 队列轮转 3.2 系统调用 3.3 工作量窃取 4.GOMAXPROCS设置对性能的影响 参考 前言 Gorout ...

  7. 闭包 panic recover

    闭包=函数+外层变量的引用 recover必须搭配defer使用 defer一定要在可能引发panic的语句之前定义

  8. CSS截取字段,让过长的字段结尾变成省略号(IE有效)

    text-overflow:ellipsis;overflow:hidden;<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transiti ...

  9. centos7系统上pgsql的一些报错解决方法

    1.2021-07-15 # 问题: 登录时服务器拒绝连接 psql -h 192.168.1.112 # 解决方法:修改配置文件 pg_hba.conf ,将该主机加进白名单 vi pg_hba.c ...

  10. CountDownLatch能不能在多个线程上添加await?

    在CountDownLatch类的使用过程中,发现了一个很奇怪的现象: CountDownLatch countDownLatch = new CountDownLatch(2); Runnable ...