【BZOJ1758】【WC2010】重建计划(点分治,单调队列)

题面

BZOJ

洛谷

Description

Input

第一行包含一个正整数N,表示X国的城市个数. 第二行包含两个正整数L和U,表示政策要求的第一期重建方案中修建道路数的上下限 接下来的N-1行描述重建小组的原有方案,每行三个正整数Ai,Bi,Vi分别表示道路(Ai,Bi),其价值为Vi 其中城市由1..N进行标号

Output

输出最大平均估值,保留三位小数

Sample Input

4

2 3

1 2 1

1 3 2

1 4 3

Sample Output

2.500

HINT

N<=100000,1<=L<=U<=N-1,Vi<=1000000

题解

我这鬼代码在BZOJ上跑不过去

因为\(BZOJ\)添加了一组很鬼畜的数据,导致\(BZOJ\)上会\(TLE\)

洛谷上能过。

表示完全不会点分治了,这道题目就当复习用。

每次我们二分一个答案,将所有的边权全部减去这个二分的值

此时题目相当于询问是否存在一条边数在\([L,U]\)之间,权值和大于\(0\)的路径。

考虑每个分治重心的贡献,依次计算当前重心的每一棵子树,

求出所有点的深度(经过的边数),以及权值和

对于每个深度,维护一个前面所有子树的最大权值和。

为了方便计算,按照所有点按照深度排序,这样就用\(bfs\)便利子树就行了。

开始考虑前面的所有子树与当前子树的贡献

用一个指针从大到小维护所有可以的前面子树中的链

同时用单调队列维护一下单调性

每次取出满足经过的边数在\([L,U]\)之间,并且权值和最大的边出来进行组合,计算一下是否满足二分的答案就好了。。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define RG register
#define MAX 111111
inline int read()
{
RG int x=0,t=1;RG char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=-1,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return x*t;
}
int n,L,U;
double ans;
struct Line{int v,next,w;}e[MAX<<1];
int h[MAX],cnt=1;
inline void Add(int u,int v,int w){e[cnt]=(Line){v,h[u],w};h[u]=cnt++;}
int size[MAX],Size,root,mx,MD;
bool vis[MAX];
double t[MAX],dis[MAX];
void Getroot(int u,int ff)
{
size[u]=1;int ret=1;
for(int i=h[u];i;i=e[i].next)
{
int v=e[i].v;if(vis[v]||v==ff)continue;
Getroot(v,u);size[u]+=size[v];
ret=max(ret,size[v]);
}
ret=max(ret,Size-size[u]);
if(mx>ret)mx=ret,root=u;
}
int Q[MAX],H,T,Vis[MAX],dep[MAX];
void bfs(int u,double d)
{
Q[H=T=1]=u;Vis[u]=true;
while(H<=T)
{
int u=Q[H++];
for(int i=h[u];i;i=e[i].next)
{
int v=e[i].v;if(vis[v]||Vis[v])continue;
dep[v]=dep[u]+1;dis[v]=dis[u]+e[i].w-d;
Q[++T]=v;Vis[v]=true;
}
}
}
int q[MAX];
bool check(int u,double d)
{
bool fl=false;int md=0;
for(int ee=h[u];ee&&!fl;ee=e[ee].next)
{
int v=e[ee].v;if(vis[v])continue;
dis[v]=e[ee].w-d;dep[v]=1;
bfs(v,d);
int hh=1,tt=0,j=md;
for(int i=1;i<=T;++i)
{
while(j>=0&&j+dep[Q[i]]>=L)
{
while(hh<=tt&&t[q[tt]]<t[j])--tt;
q[++tt]=j;--j;
}
while(hh<=tt&&dep[Q[i]]+q[hh]>U)++hh;
if(hh<=tt&&dis[Q[i]]+t[q[hh]]>=0)fl=true;
}
md=max(md,dep[Q[T]]);
for(int i=1;i<=T;++i)
{
Vis[Q[i]]=false;
t[dep[Q[i]]]=max(t[dep[Q[i]]],dis[Q[i]]);
}
}
for(int i=1;i<=md;++i)t[i]=-1e12;
return fl;
}
void Calc(int u)
{
double l=ans,r=MD;
while(r-l>1e-4)
{
double mid=(l+r)/2;
if(check(u,mid))l=mid;
else r=mid;
}
ans=l;
}
void DFS(int u)
{
vis[u]=true;Calc(u);
for(int i=h[u];i;i=e[i].next)
{
int v=e[i].v;if(vis[v])continue;
Size=size[v];mx=n;Getroot(v,0);
DFS(root);
}
}
int main()
{
n=read();L=read();U=read();
for(int i=1;i<n;++i)
{
int u=read(),v=read(),w=read();
Add(u,v,w);Add(v,u,w);MD=max(MD,w);
}
Size=mx=n;Getroot(1,0);
DFS(root);
printf("%.3lf\n",ans);
return 0;
}

【BZOJ1758】【WC2010】重建计划(点分治,单调队列)的更多相关文章

  1. [BZOJ1758][WC2010]重建计划(点分治+单调队列)

    点分治,对于每个分治中心,考虑求出经过它的符合长度条件的链的最大权值和. 从分治中心dfs下去取出所有链,为了防止两条链属于同一个子树,我们一个子树一个子树地处理. 用s1[i]记录目前分治中心伸下去 ...

  2. P4292 [WC2010]重建计划 点分治+单调队列

    题目描述 题目传送门 分析 看到比值的形式就想到 \(01分数规划\),二分答案 设当前的值为 \(mids\) 如果存在\(\frac{\sum _{e \in S} v(e)}{|S|} \geq ...

  3. BZOJ1758: [Wc2010]重建计划

    题解: 这题我居然做了一星期?... 平均值的极值其实也可以算是一种分数规划,只不过分母上b[i]=1 然后我们就可以二分这个值.类似与 HNOI最小圈 如果没有 链的长度的限制的话,我们直接两遍df ...

  4. BZOJ1758 WC2010 重建计划 二分答案、点分治、单调队列

    传送门 看到平均数最大,自然地想到二分答案.那么我们的$check$函数就是要求:是否存在一条长度在$[L,U]$的路径,满足其权值和$\geq 0$. 看到长度在$[L,U]$,自然地想到点分治求解 ...

  5. BZOJ1758: [Wc2010]重建计划(01分数规划+点分治+单调队列)

    题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1758 01分数规划,所以我们对每个重心进行二分.于是问题转化为Σw[e]-mid>=0, ...

  6. bzoj1758 [Wc2010]重建计划 & bzoj2599 [IOI2011]Race

    两题都是树分治. 1758这题可以二分答案avgvalue,因为avgvalue=Σv(e)/s,因此二分后只需要判断Σv(e)-s*avgvalue是否大于等于0,若大于等于0则调整二分下界,否则调 ...

  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. bzoj 1758 [Wc2010]重建计划 分数规划+树分治单调队列check

    [Wc2010]重建计划 Time Limit: 40 Sec  Memory Limit: 162 MBSubmit: 4345  Solved: 1054[Submit][Status][Disc ...

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

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

随机推荐

  1. 【JUC源码解析】ConcurrentHashMap

    简介 支持并发的哈希表.其中包括红黑树,扩容,分槽计数等知识点. 源码分析 常量 private static final int MAXIMUM_CAPACITY = 1 << 30; ...

  2. javaweb(十四)——JSP原理

    一.什么是JSP? JSP全称是Java Server Pages,它和servle技术一样,都是SUN公司定义的一种用于开发动态web资源的技术. JSP这门技术的最大的特点在于,写jsp就像在写h ...

  3. Linux 内核3.10.5 专场

    今天本人十分靠谱地下载了linux 内核的3.10.5版本,这个版本是最新的稳定版. 听路飞大虾(哪个路飞?就是那个戴草帽的橡胶小伙,航海很多时候都很空闲的,于是最近他也开始研读linux 内核了.) ...

  4. PPM、PGM、PBM图像格式剖析

    今天突然需要用到PPM这个图像文件格式,之前没见过,在此记录一下. PPM.PGM.PBM这三个图像文件格式很少见,其实也不难,分别用于彩色图像.灰度图像.二值图像.这里以PPM格式为例. PPM格式 ...

  5. mysql把一字段拆分为多行

    sql语句 select a.house_no as '房子',substring_index(substring_index(a.name,',',b.help_topic_id+1),',',-1 ...

  6. Windows下使用7-zip命令自动备份文件

    在上一篇博文中,介绍了使用WinRAR自动备份文件,后来改用了腾讯云服务器,上面默认没有安装WinRAR,只有7-zip,又不想在服务器上安装许多软件,就查了下7-zip的命令,贴出来备忘~ 系统环境 ...

  7. USACO 3.2.6 Sweet Butter 香甜的黄油(最短路)

    Description 农夫John发现做出全威斯康辛州最甜的黄油的方法:糖.把糖放在一片牧场上,他知道N(1<=N<=500)只奶牛会过来舔它,这样就能做出能卖好价钱的超甜黄油.当然,他 ...

  8. python 二维矩阵及转byte知识点

    1.注意python中的数组和list形式混合: 数组在numpy里面: 2.二维数组这样定义可以修改固定位置的值: rawDataArray_temp = [([0]*nIRImageWidth)f ...

  9. Alpha冲刺——第八天

    Alpha第八天 听说 031502543 周龙荣(队长) 031502615 李家鹏 031502632 伍晨薇 031502637 张柽 031502639 郑秦 1.前言 任务分配是VV.ZQ. ...

  10. A9

    今日内容: 解决队友提出的问题 明日计划: 商讨界面还有哪些不足的地方 困难: 每天大部分时间被电工实习占走了