博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
UOJ#276. 【清华集训2016】汽水 二分答案 点分治
阅读量:5293 次
发布时间:2019-06-14

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

原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ276.html

题解

首先,读入的时候就将所有的 $w_i$ 减掉 $k$ 。

于是我们要求的就是平均值最接近 0 的。

直接点分治,然后得到一些一端为当前点分中心的路径,设 $a,b$ 为其中两条路径,设 $v_a,v_b$ 为路径的边权和,$t_a,t_b$ 为路径的边数。

二分一个答案,假设差别**小于** $A$。由于题目要求的是下取整,所以我们为了方便,设的是**小于** $A$ ,这样做,最终只需要把答案减一就好了。

那么,如果合并路径 $a,b$ 可以满足条件,那么就会满足:

$$\left|\cfrac{v_a+v_b}{t_a+t_b}\right|<A\\|v_a+v_b|<A(t_a+t_b)\\=\begin{cases}v_a-At_a+v_b-At_b<0\ \ \ \ \ \ (v_a+v_b\geq 0)\\v_a+At_a+v_b+At_b>0\ \ \ \ \ \ (v_a+v_b<0)\end{cases}$$

也就是说,我们只需要对于正的 $v_a$ 和负的 $v_a$ 分开考虑,在保证取到右侧条件的基础上,维护一下最大最小值之类的东西就好了。

具体还是看代码吧。

代码

#include 
#define mp make_pair#define fi first#define se secondusing namespace std;typedef long long LL;LL read(){ LL x=0; char ch=getchar(); while (!isdigit(ch)) ch=getchar(); while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar(); return x;}const int N=50005;const LL INF=1LL<<60;int n;LL K,ans=INF;vector
> e[N];int vis[N],size[N],Maxsize[N],root,Size;void get_root(int x,int pre){ size[x]=1,Maxsize[x]=0; for (auto E : e[x]) if (E.fi!=pre&&!vis[E.fi]){ get_root(E.fi,x); size[x]+=size[E.fi]; Maxsize[x]=max(Maxsize[x],size[E.fi]); } Maxsize[x]=max(Maxsize[x],Size-size[x]); if (Maxsize[x]
=0) posi[++pc]=Node{cnt,S,ID}; else nega[++nc]=Node{cnt,S,ID}; for (auto E : e[x]) if (E.fi!=pre&&!vis[E.fi]) dfs(E.fi,x,cnt+1,S+E.se,ID);}pair
_1,_2;void ckMax(pair
_3){ if (_3.se>_1.se){ if (_3.fi!=_1.fi) _2=_1; _1=_3; } else if (_3.se>_2.se&&_3.fi!=_1.fi) _2=_3;}void ckMin(pair
_3){ if (_3.se<_1.se){ if (_3.fi!=_1.fi) _2=_1; _1=_3; } else if (_3.se<_2.se&&_3.fi!=_1.fi) _2=_3;}int check(LL x){ _1=_2=mp(0,INF); for (int i=1,j=nc;i<=pc;i++){ while (j>0&&posi[i].v+nega[j].v>=0) ckMin(mp(nega[j].id,nega[j].v-x*nega[j].t)),j--; if (posi[i].v-x*posi[i].t+(posi[i].id==_1.fi?_2.se:_1.se)<0) return 1; ckMin(mp(posi[i].id,posi[i].v-x*posi[i].t)); } _1=_2=mp(0,-INF); for (int i=pc,j=1;i>=1;i--){ while (j<=nc&&posi[i].v+nega[j].v<0) ckMax(mp(nega[j].id,nega[j].v+x*nega[j].t)),j++; if (posi[i].v+x*posi[i].t+(posi[i].id==_1.fi?_2.se:_1.se)>0) return 1; ckMin(mp(posi[i].id,posi[i].v+x*posi[i].t)); } return 0;}void solve(int x){ Maxsize[0]=n+1; root=pc=nc=0; get_root(x,0); vis[x=root]=1; posi[++pc]=Node{0,0,x}; for (auto E : e[x]) if (!vis[E.fi]) dfs(E.fi,x,1,E.se,E.fi); sort(posi+1,posi+pc+1); sort(nega+1,nega+nc+1); LL L=1,R=ans-1,mid; while (L<=R){ mid=(L+R)>>1; if (check(mid)) R=mid-1; else L=mid+1; } ans=min(ans,L); for (auto E : e[x]) if (!vis[E.fi]) Size=size[E.fi],solve(E.fi);}int main(){ Size=n=read(),K=read(); for (int i=1;i

  

转载于:https://www.cnblogs.com/zhouzhendong/p/UOJ276.html

你可能感兴趣的文章
Tomcat加载JSP原理
查看>>
java文件相关操作
查看>>
对 HTTP 304 的理解
查看>>
深入理解css中的margin属性
查看>>
C++ 删除字符串的两种实现方式
查看>>
电容选型
查看>>
ORA-01502: 索引'P_ABCD.PK_WEB_BASE'或这类索引的分区处于不可用状态
查看>>
Spring EL hello world实例
查看>>
百度地图API地理位置和坐标转换
查看>>
MyBatis学习总结(六)——调用存储过程
查看>>
code-代码平台服务器路径
查看>>
离线安装 Visual Studio Express 而不下载整个镜像文件的方法(转载)
查看>>
2014年国际数学家大会台历
查看>>
[数分提高]2014-2015-2第3教学周第1次课
查看>>
2017-2018-2偏微分方程复习题解析10
查看>>
PHP处理Excel
查看>>
【JavaScript吉光片羽】--- 滑动条
查看>>
老生常谈: Javascript 面向对象编程初探(一)--- 封装
查看>>
Java抽象类和接口的比较
查看>>
XML DataBase之BaseX相关
查看>>