博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【BZOJ1758】【WC2010】重建计划(点分治,单调队列)
阅读量:4884 次
发布时间:2019-06-11

本文共 2703 字,大约阅读时间需要 9 分钟。

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

题面

Description

img

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
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;#define ll long long#define RG register#define MAX 111111inline 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]]
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

转载于:https://www.cnblogs.com/cjyyb/p/8820414.html

你可能感兴趣的文章
cocos2dx内存管理
查看>>
error: variably modified 'table' at file scope
查看>>
sqlite 下载地址
查看>>
ViewPager的addOnPageChangeListener方法详解
查看>>
一个很好用的GD图像处理类image.class.php,推荐给大家
查看>>
shell 数值计算
查看>>
WebApi的多版本管理
查看>>
转:『代码』JS封装 Ajax级联下拉列表
查看>>
清北学堂2017NOIP冬令营入学测试P4749 C’s problem(c)
查看>>
自动编号维护SNRO
查看>>
将支付宝发来的数据生成有序数列
查看>>
事后诸葛亮
查看>>
ubuntu16.04下安装mysql详细步骤
查看>>
教练技术的小应用
查看>>
关于手机音乐软件问卷调查的分析报告
查看>>
pat02-线性结构2. 一元多项式求导 (25)
查看>>
Leetcode 28. Implement strStr()
查看>>
python中的ConfigParser模块
查看>>
IOS多线程 总结 -------------核心代码(GCD)
查看>>
图片上传iOS
查看>>