【BZOJ3672】[Noi2014]购票 树分治+斜率优化
【BZOJ3672】[Noi2014]购票
Description
Input
第 1 行包含2个非负整数 n,t,分别表示城市的个数和数据类型(其意义将在后面提到)。输入文件的第 2 到 n 行,每行描述一个除SZ之外的城市。其中第 v 行包含 5 个非负整数 f_v,s_v,p_v,q_v,l_v,分别表示城市 v 的父亲城市,它到父亲城市道路的长度,票价的两个参数和距离限制。请注意:输入不包含编号为 1 的SZ市,第 2 行到第 n 行分别描述的是城市 2 到城市 n。
Output
输出包含 n-1 行,每行包含一个整数。其中第 v 行表示从城市 v+1 出发,到达SZ市最少的购票费用。同样请注意:输出不包含编号为 1 的SZ市。
Sample Input
1 2 20 0 3
1 5 10 100 5
2 4 10 10 10
2 9 1 100 10
3 5 20 100 10
4 4 20 0 10
Sample Output
150
70
149
300
150
HINT
对于所有测试数据,保证 0≤pv≤106,0≤qv≤1012,1≤fv<v;保证 0<sv≤lv≤2×1011,且任意城市到SZ市的总路程长度不超过 2×1011。
输入的 t 表示数据类型,0≤t<4,其中:
当 t=0 或 2 时,对输入的所有城市 v,都有 fv=v-1,即所有城市构成一个以SZ市为终点的链;
当 t=0 或 1 时,对输入的所有城市 v,都有 lv=2×1011,即没有移动的距离限制,每个城市都能到达它的所有祖先;
当 t=3 时,数据没有特殊性质。
n=2×10^5
题解:做这种题就怕突然灵光一现,然后自己yy了一发,到对拍1w组的时候才发现自己的做法完全GG,于是只好重写。。。
先分享一下做这道题的思路(前置技能:BZOJ1492货币兑换),如果着急和MM约会,可以直接看最后两段。
——————————————从此处开始略过——————————————
蒟蒻的独白:“不就是将cdq分治换成树分治嘛,有什么难的?这式子也太水了:用dep[i]表示根到i的距离,f[i]表示从i到根的最小购票费用,显然
$f[i]=min(f[j]+(dep[i]-dep[j])*p[i]+q[i]) \rightarrow f[j]=dep[j]*p[i]+f[i]-q[i]-dep[i]*p[i]$
式子都推出来了,搞呗!当我们以x为分治中心时,可选的i就是x子树中的所有点,可选的j就是根到i路径上的所有点(当然要满足i,j的距离<=li啦~),然后我就先递归分治x的父亲的那部分(在有根树中好像这个不能叫子树吧?),然后将x到根路径上的所有的点都拎出来维护个凸包,枚举x子树中的所有点,然后每个点都在那个凸包上二分一下,就完事啦!WA。
“突然发现,我们在搞凸包的时候,会丢掉很多点,新加入一些深度更小的点,但是由于有距离限制,这些深度更小的点不能更新x子树中的一些点,于是,这就要求我们将x子树中的点也都拎出来,一起搞。
“思路来了,我们将x到根路径上的所有点都用数组A存起来,x子树中的点都用数组B存起来,并按照(dep-l)排好序,那么我们同时扫这两个数组,边维护凸包边二分更新答案,感觉很棒!WA。
“惊讶的发现!x居然是降序的!无可奈何,重新搞。WA。
“1w组对拍都过了?woc用叉积会爆long long!无可奈何,用double。AC。”
————————————————省略结束————————————————
总结一下全过程(翻译一下代码):
1.当我们以x为分治中心时,先从网上一直延伸直到第一个已经访问过的节点,然后将这个最高点记录下来(一会才用!),然后分治处理x的父亲那部分
2.处理完父亲后,我们将从x到那个最高点的路径上的点都拎出来扔到数组A中,再DFSx的子树中的点,放到B中,并按dep-l从大到小排序。
3.同时扫A和B,进行斜率优化
4.分治处理x的子树
本人的代码不可读性还是比较高的,WA的同学请注意:在我们拎出x子树中的点时,就算访问到之前被标记过(做过分治中心)的点时也要将它放入数组中更新,只是不继续延伸下去。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#include <algorithm>
#define x(_) (dep[_])
#define y(_) (f[_])
using namespace std;
const int maxn=200010;
typedef long long ll;
int n,m,cnt,maxx,tot,root;
int fa[maxn],siz[maxn],to[maxn],next[maxn],head[maxn],A[maxn],st[maxn],vis[maxn],B[maxn];
ll val[maxn],dep[maxn],len[maxn],p[maxn],q[maxn],lim[maxn],f[maxn];
ll rd()
{
ll ret=0; char gc=getchar();
while(gc<'0'||gc>'9') gc=getchar();
while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar();
return ret;
}
bool cmp(int a,int b)
{
return dep[a]-lim[a]>dep[b]-lim[b];
}
void add(int a,int b)
{
to[cnt]=b,next[cnt]=head[a],head[a]=cnt++;
}
void getr(int x,int fa)
{
siz[x]=1;
int i,mx=0;
for(int i=head[x];i!=-1;i=next[i])
{
if(vis[to[i]]||to[i]==fa) continue;
getr(to[i],x),siz[x]+=siz[to[i]],mx=max(mx,siz[to[i]]);
}
if(maxx>max(mx,tot-siz[x])) maxx=max(mx,tot-siz[x]),root=x;
}
void getB(int x)
{
B[++B[0]]=x;
if(vis[x]) return ;
for(int i=head[x];i!=-1;i=next[i]) getB(to[i]);
}
double getk(int a,int b)
{
if(x(a)==x(b)) return 1e15*(y(a)>y(b)?1.0:-1.0);
else return (double)(y(a)-y(b))/(x(a)-x(b));
}
void calc(int x)
{
if(!m) return ;
int mid,l=1,r=m;
double k=p[x];
while(l<r)
{
mid=l+r>>1;
if(getk(A[mid],A[mid+1])>k) l=mid+1;
else r=mid;
}
f[x]=min(f[x],f[A[l]]+(dep[x]-dep[A[l]])*p[x]+q[x]);
}
void dfs(int x)
{
vis[x]=1;
int i,j,top=x;
while(top!=1&&!vis[fa[top]]) top=fa[top];
if(x!=top) maxx=1<<30,tot=siz[top]-siz[x],getr(top,0),dfs(root);
if(top!=1) top=fa[top];
st[st[0]=1]=x;
while(st[st[0]]!=top) st[st[0]+1]=fa[st[st[0]]],st[0]++;
for(B[0]=0,i=head[x];i!=-1;i=next[i]) getB(to[i]);
sort(B+1,B+B[0]+1,cmp);
for(m=0,i=1,j=1;i<=st[0];i++)
{
for(;j<=B[0]&&dep[st[i]]<dep[B[j]]-lim[B[j]];j++) calc(B[j]);
while(m>1&&getk(A[m-1],A[m])<=getk(A[m],st[i])) m--;
A[++m]=st[i];
}
for(;j<=B[0];j++) calc(B[j]);
for(i=head[x];i!=-1;i=next[i]) if(!vis[to[i]]) maxx=1<<30,tot=siz[to[i]],getr(to[i],x),dfs(root);
}
int main()
{
n=rd(),rd();
int i;
memset(head,-1,sizeof(head));
for(i=2;i<=n;i++)
{
fa[i]=rd(),len[i]=rd(),p[i]=rd(),q[i]=rd(),lim[i]=rd();
add(fa[i],i);
dep[i]=dep[fa[i]]+len[i];
}
memset(f,0x3f,sizeof(f)),f[1]=0;
maxx=1<<30,tot=n,getr(1,0),dfs(root);
for(i=2;i<=n;i++) printf("%lld\n",f[i]);
return 0;
}
【BZOJ3672】[Noi2014]购票 树分治+斜率优化的更多相关文章
- 【BZOJ-3672】购票 树分治 + 斜率优化DP
3672: [Noi2014]购票 Time Limit: 30 Sec Memory Limit: 512 MBSubmit: 1177 Solved: 562[Submit][Status][ ...
- BZOJ_3672_ [Noi2014]购票_CDQ分治+斜率优化
BZOJ_3672_ [Noi2014]购票_CDQ分治+斜率优化 Description 今年夏天,NOI在SZ市迎来了她30周岁的生日.来自全国 n 个城市的OIer们都会从各地出发,到SZ市参 ...
- UOJ#7. 【NOI2014】购票 点分治 斜率优化 凸包 二分
原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ7.html 题解 这题是Unknown的弱化版. 如果这个问题出在序列上,那么显然可以CDQ分治 + 斜率 ...
- [NOI2014]购票 「树上斜率优化」
首先易得方程,且经过变换有 $$\begin{aligned} f_i &= \min\limits_{dist_i - lim_i \le dist_j} \{f_j + (dist_i - ...
- BZOJ3672: [Noi2014]购票(CDQ分治,点分治)
Description 今年夏天,NOI在SZ市迎来了她30周岁的生日.来自全国 n 个城市的OIer们都会从各地出发,到SZ市参加这次盛会. 全国的城市构成了一棵以SZ市为根的有根树 ...
- bzoj4311向量(线段树分治+斜率优化)
第二道线段树分治. 首先设当前向量是(x,y),剩余有两个不同的向量(u1,v1)(u2,v2),假设u1>u2,则移项可得,若(u1,v1)优于(u2,v2),则-x/y>(v1-v2) ...
- 【BZOJ3672】【NOI2014】购票(线段树,斜率优化,动态规划)
[BZOJ3672][NOI2014]购票(线段树,斜率优化,动态规划) 题解 首先考虑\(dp\)的方程,设\(f[i]\)表示\(i\)的最优值 很明显的转移\(f[i]=min(f[j]+(de ...
- BZOJ3672 [Noi2014]购票 【点分治 + 斜率优化】
题目链接 BZOJ3672 题解 如果暂时不管\(l[i]\)的限制,并假使这是一条链 设\(f[i]\)表示\(i\)节点的最优答案,我们容易得到\(dp\)方程 \[f[i] = min\{f[j ...
- bzoj千题计划251:bzoj3672: [Noi2014]购票
http://www.lydsy.com/JudgeOnline/problem.php?id=3672 法一:线段树维护可持久化单调队列维护凸包 斜率优化DP 设dp[i] 表示i号点到根节点的最少 ...
随机推荐
- mysql优化30条建议
1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引. 2.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索 ...
- Python 面向对象一(转载)
一.前言 1.面向对象是一种编程方式,此编程方式的实现是基于对 类 和 对象 的使用 2.类 是一个模板,模板中包装了多个“函数”供使用(可以讲多函数中公用的变量封装到对象中) 3.对象,根据模板创建 ...
- [转载]SecureCRT 绝佳配色方案, 保护你的眼睛
FROM:http://blog.csdn.net/zklth/article/details/8937905 SecureCRT 绝佳配色方案, 保护你的眼睛 关键词:SecureCRT配色, ...
- Intellij Idea如何不显示.idea target文件夹
Intellij Idea如何不显示.idea target文件夹 学习了:https://jingyan.baidu.com/article/ceb9fb108e26958cac2ba047.htm ...
- iOS小技巧 - 为按钮设置不同状态下的背景色
我们知道直接在Storyboard中设置按钮的背景色是不能根据不同状态来更改的,那问题来了,如果我们需要在不同的状态下(比如按钮没有被按下或者被按下),使得按钮呈现不同的背景色怎么办? 比如上图左边是 ...
- Linux非阻塞IO(七)使用epoll重新实现客户端
使用poll与epoll的区别主要在于: poll可以每次重新装填fd数组,但是epoll的fd是一开始就加入了,不可能每次都重新加入 于是采用这种策略: epoll除了listenfd一开始就监听r ...
- swift -NavigationController,代理传值
// // ViewController.swift // NavigationController // import UIKit import Foundation class ViewContr ...
- curl测试Docker容器连通性
通过curl来测试docker对外访问是否正常,这里测试Docker tomcat容器访问: [root@mysqlserver ~]# curl http://172.17.0.8:8080 < ...
- Ubuntu Server 命令行下显示中文乱码(菱形)解决办法
如果Ubuntu Server在安装过程中,选择的是中文(很多新手都会在安装时选择中文,便于上手),这样在完成安装后,系统默认的语言将会是中文zh_CN.UTF- 8.但问题是我们安装的是服务器,只需 ...
- 最常用的几个python库--学习引导
核心库 1.NumPy 当我们用python来处理科学计算任务时,不可避免的要用到来自SciPy Stack的帮助.SciPy Stack是一个专为python中科学计算而设计的软件包,注意不要将它 ...