【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. python编辑三级目录

    一.需求分析 三级目录要能够实现以下要求: 显示根目录,任何子目录中都可以通过输入b字符来返回根目录 任何子目录中都可以通过输入q字符来返回上一级目录 主目录进入子目录后,系统能够打印子目录,根据指打 ...

  2. linux云主机小技巧

    微信服务器安装 安装库 python 3.5环境下 pip安装web.py时 会报错 "no module named "utils" 等问题 更换命令为“pip ins ...

  3. LeetCode 148——排序链表

    1. 题目 2. 解答 2.1 快速排序 可参考 快速排序和归并排序 中的第一种快速排序思想,与在数组中排序有两点不同. 第一,我们需要取最后一个元素作为主元,在数组中可以直接访问到最后一个元素,但在 ...

  4. java-length 、length()、size()的区别

    public static void main(String[] args) { //length .length().size()的区别 //length属性 针对数组长度 String a[]={ ...

  5. Fedora 26/27/28网易云音乐安装

    信息从 https://www.southcity-oldboy.com/1474.html获取,感谢站长南城旧少年! 以下为前辈网页上的内容 1.安装 RPM Fusion 源 (free): ht ...

  6. hibernate.hbm.xml文件配置入门小结(1)

    在Hibernate中,各表的映射文件xxx.hbm.xml可以通过工具生成,例如在使用MyEclipse开发时,它提供了自动生成映射文件的工具. hibernate.hbm.xml文件的基本结构如下 ...

  7. React Native 【学习总结】-【常用命令】

    前言 刚接触RN,相信很多人无从下手,不知道下一步要干什么,能干什么,本次学习围绕这个问题,将RN的常用命令总结一下,帮助你快速上手 架构理解 光知道命令的作用,远远不够,如果知道命令背后的意义,才能 ...

  8. loadrunner socket协议问题归纳(0)

    一.概述         Loadrunner拥有极为丰富的工具箱,供予我们制造出各种奇妙魔法的能力.其中就有此次要讨论的socket套接字操作.     二.socket概述         soc ...

  9. linux下svn操作(专)

    原文地址:https://www.cnblogs.com/clicli/p/5913330.html svn命令在linux下的使用SVN软件版本管理 1.将文件checkout到本地目录svn ch ...

  10. “Hello World!”团队召开的第六次会议

    团队“Hello World!”团队召开的第六次会议. 博客内容: 一.会议时间 二.会议地点 三.会议成员 四.会议内容 五.Todo List 六.会议照片 七.燃尽图 一.会议时间 2017年1 ...