【BZOJ4738/UOJ#276】汽水(点分治,分数规划)
【BZOJ4738/UOJ#276】汽水(点分治,分数规划)
题面
题解
今天考试的题目,虽然说是写完了,但是感觉还是半懂不懂的来着。
代码基本照着\(Anson\)爷的码的,orz。(然后Anson爷的UOJrk1不保了)
首先拿到这道题目的一个比较显然的思路就是分数规划二分答案之后再点分治考虑是否有满足二分条件的链。
考虑条件是什么呢?(接下来写的时候为了方便,把所有的边权默认全部减去了一个\(K\),这样子就是要求平均值的绝对值最小的链了)
因为要的是绝对值最小,那么我们二分了这个绝对值\(mid\)之后,只有两种情况,要么平均值小于\(0\),并且大于\(-mid\),或者大于\(0\)并且小于\(mid\)。移项之后变成了权值和减去边的数量乘以二分值的结果与\(0\)的大小关系。这两种情况分开考虑计算。
那么,我们要做的就是确定分治重心之后,求出过重心的所有链。先考虑其子树中的每一个点,记录三元组,分别表示权值和,边的数量,以及从哪个子树来的(显然只有两个不同子树中的链才能拼在一起),按照权值和排序之后考虑如何拼接。以权值和大于\(0\)为例。
对于每个权值和大于\(0\)的链从小往大加入贡献,找到权值最小的链满足与当前链的权值和大于\(0\),因为这个最小值是一段区间,所以维护下来两个最大值与当前权值为正的链拼接\(check\)是否满足条件即可。
好难说清楚啊,看下代码就懂了。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;
#define ll long long
#define MAX 55000
inline ll read()
{
ll x=0;bool t=false;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}
struct Line{int v,next;ll w;}e[MAX<<1];
int h[MAX],cnt=1;
inline void Add(int u,int v,ll w){e[cnt]=(Line){v,h[u],w};h[u]=cnt++;}
int sz[MAX],rt,Sz,mx;bool vis[MAX];
struct Node{ll v,s,t;}S[MAX];int top;
bool operator<(Node a,Node b){return a.s<b.s;}
ll ans=1ll<<60,K;int n;
void getroot(int x,int ff)
{
sz[x]=1;int ret=0;
for(int i=h[x];i;i=e[i].next)
{
int v=e[i].v;if(v==ff||vis[v])continue;
getroot(v,x);sz[x]+=sz[v];
ret=max(ret,sz[v]);
}
ret=max(ret,Sz-sz[x]);
if(ret<mx)mx=ret,rt=x;
}
void dfs(int u,int fa,int dep,ll sum,int tp)
{
S[++top]=(Node){dep,sum,tp};
for(int i=h[u];i;i=e[i].next)
if(e[i].v!=fa&&!vis[e[i].v])
dfs(e[i].v,u,dep+1,sum+e[i].w,tp);
}
int pos;
pair<ll,ll> A,B;
void upd(pair<ll,ll> c)
{
if(c.first<B.first)
{
if(c.first<A.first)
{
if(c.second!=A.second)B=A;
A=c;
}
else if(c.second!=A.second)B=c;
}
}
bool check1(ll k)
{
A=B=make_pair(1ll<<60,0);
for(int i=pos,j=pos-1;i<=top;++i)
{
while(j&&S[i].s+S[j].s>=0)
upd(make_pair(S[j].s-k*S[j].v,S[j].t)),--j;
if((A.second==S[i].t?B.first:A.first)<k*S[i].v-S[i].s)return true;
upd(make_pair(S[i].s-k*S[i].v,S[i].t));
}
return false;
}
bool check2(ll k)
{
A=B=make_pair(1ll<<60,0);
for(int i=pos-1,j=pos;i;--i)
{
while(j<=top&&S[i].s+S[j].s<0)upd(make_pair(-S[j].s+k*S[j].v,S[j].t)),++j;
if((A.second==S[i].t?B.first:A.first)<-k*S[i].v+S[i].s)return true;
upd(make_pair(-S[i].s+k*S[i].v,S[i].t));
}
return false;
}
void Divide(int x)
{
vis[x]=true;S[top=1]=(Node){0,0,0};
for(int i=h[x];i;i=e[i].next)
if(!vis[e[i].v])
dfs(e[i].v,x,1,e[i].w,e[i].v);
sort(&S[1],&S[top+1]);
for(pos=1;pos<=top&&S[pos].s<0;++pos);
ll l=1,r=ans-1;
while(l<=r)
{
ll mid=(l+r)>>1;
if(check1(mid)||check2(-mid))r=mid-1;
else l=mid+1;
}
ans=min(ans,l);
for(int i=h[x];i;i=e[i].next)
if(!vis[e[i].v])
Sz=mx=sz[e[i].v],getroot(e[i].v,x),Divide(rt);
}
int main()
{
n=read();K=read();
for(int i=1;i<n;++i)
{
int u=read(),v=read();ll w=read()-K;
Add(u,v,w);Add(v,u,w);ans=min(ans,abs(w)+1);
}
Sz=mx=n;getroot(1,0);
Divide(1);
printf("%lld\n",ans-1);
return 0;
}
【BZOJ4738/UOJ#276】汽水(点分治,分数规划)的更多相关文章
- BZOJ.4738.[清华集训2016]汽水(点分治 分数规划)
BZOJ UOJ 记\(val_i\)是每条边的边权,\(s\)是边权和,\(t\)是经过边数,\(k\)是给定的\(k\). 在点分治的时候二分答案\(x\),设\(|\frac st-k|=x\) ...
- [UOJ#276][清华集训2016]汽水[分数规划+点分治]
题意 给定一棵 \(n\) 个点的树,给定 \(k\) ,求 \(|\frac{\sum w(路径长度)}{t(路径边数)}-k|\)的最小值. \(n\leq 5\times 10^5,k\leq ...
- uoj#276. 【清华集训2016】汽水(分数规划+点分治)
传送门 没想到点分治那一层-- 首先不难发现这是个分数规划,先把所有的边长减去\(k\),二分答案,设为\(mid\),就是要求路径平均值\(ans\in[-mid,mid]\) 先来考虑\(ans\ ...
- 【UOJ276】【清华集训2016】汽水(分数规划+点分治)
点此看题面 大致题意: 给你一棵树,要求你选择一条树上路径,使得这条路径上边权的平均值与定值\(k\)的差的绝对值最小.求出这个最小值. 分数规划 看到平均值,首先就应该想到分数规划吧. 我们二分答案 ...
- [UOJ#276]【清华集训2016】汽水
[UOJ#276][清华集训2016]汽水 试题描述 牛牛来到了一个盛产汽水的国度旅行. 这个国度的地图上有 \(n\) 个城市,这些城市之间用 \(n−1\) 条道路连接,任意两个城市之间,都存在一 ...
- 【BZOJ 1758】【WC 2010】重建计划 分数规划+点分治+单调队列
一开始看到$\frac{\sum_{}}{\sum_{}}$就想到了01分数规划但最终还是看了题解 二分完后的点分治,只需要维护一个由之前处理过的子树得出的$tb数组$,然后根据遍历每个当前的子树上的 ...
- [WC2010]重建计划(分数规划+点分治+单调队列)
题目大意:给定一棵树,求一条长度在L到R的一条路径,使得边权的平均值最大. 题解 树上路径最优化问题,不难想到点分治. 如果没有长度限制,我们可以套上01分数规划的模型,让所有边权减去mid,求一条路 ...
- P2877 [USACO07JAN]牛校Cow School(01分数规划+决策单调性分治)
P2877 [USACO07JAN]牛校Cow School 01分数规划是啥(转) 决策单调性分治,可以解决(不限于)一些你知道要用斜率优化却不会写的问题 怎么证明?可以暴力打表 我们用$ask(l ...
- [WC2010][BZOJ1758]重建计划-[二分+分数规划+点分治]
Description 传送门 Solution 看到那个式子,显然想到分数规划...(不然好难呢) 然后二分答案,则每条边的权值设为g(e)-ans.最后要让路径长度在[L,U]范围内的路径权值&g ...
随机推荐
- Linux mount 命令
mount 命令用来挂载文件系统.其基本命令格式为:mount -t type [-o options] device dirdevice:指定要挂载的设备,比如磁盘.光驱等.dir:指定把文件系统挂 ...
- Linux运维笔记-日常操作命令总结(2)
回想起来,从事linux运维工作已近5年之久了,日常工作中会用到很多常规命令,之前简单罗列了一些命令:http://www.cnblogs.com/kevingrace/p/5985486.html今 ...
- 完整部署CentOS7.2+OpenStack+kvm 云平台环境(2)--云硬盘等后续配置
继上一篇博客介绍了完整部署CentOS7.2+OpenStack+kvm 云平台环境(1)--基础环境搭建,本篇继续讲述后续部分的内容 1 虚拟机相关1.1 虚拟机位置介绍 openstack上创建的 ...
- SCRUM 12.22
周一,大家现在课程也比较少,今天都在非常努力地写代码. 任务分配如往常一样,我们现在基本将工作的重心放在完善已有的组件上. 成员 任务 彭林江 落实API 牛强 落实意见反馈功能测试 高雅智 测试已完 ...
- 【M2】软件工程终期总结报告——阅读作业
PhylabWeb——阅读作业 问题回顾 提问博客地址:http://www.cnblogs.com/kibbon/p/4831104.html 尚待解决的问题: Alpha/Beta,ZBB/RC阶 ...
- Spring方法级别的验证
设置验证点及验证方式(1)Spring方法级别的验证有多种验证方式,比较常用的有 @NotBlank:主要是对字符串的验证,不为null且去除空白符之后长度大于0 @NotNull:主要是对对象的验证 ...
- kNN算法学习(一)
1.首先需要一些训练样本集,例如一道问题(数据)及答案(标签),可以看做一条样本,那么多条,就是样本集 当然这里应该是一条数据及该数据所属的分类,该类别称为标签 2.现在我们已经知道数据与所属类别的对 ...
- 数学战神app(小学生四则运算app)开发需求及进度
项目名字:“数学战神” 开发环境:Android eclipse 团队名称:战神联盟 团队成员:陈思明,许家豪,王宏财,吴旭涛 在之前的四则运算APP中添加更多的实用功能,并在各种平台推广宣传. 预加 ...
- [福大软工] Z班——Beta现场答辩反馈
Beta现场答辩 互评反馈 各组对于 麻瓜制造者 的评价与建议 队伍名 评价与建议 *** 功能继续完善,二手市场有闲鱼这条大鱼,要继续体现区域性的优势 *** web端的UI很好看,但安卓和web相 ...
- Selenium IDE 宏 试用 一例
本质是宏(Macro)理念 Marco概念的广泛应用: 1.Office的Excel里的任何操作的 可以都可以用VBA编程记录下宏,然后把记录的宏,可以回放.当然也可以生成代码,比如给Excel设置单 ...