bzoj3672【NOI2014】购票
题目描述
输入格式
第 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。
输出格式
输出包含 n-1 行,每行包含一个整数。其中第 v 行表示从城市 v+1 出发,到达SZ市最少的购票费用。同样请注意:输出不包含编号为 1 的SZ市。
数据规模

题解:
- 设$v$是$u$的祖先,$dp[u] = dp[v] + (dis[u]-dis[v])*p[u] + q[u] \ , \ (dis[u]-dis[v]<=l[u])$
- 斜率优化部分:
- 假设$d[v_{1}]<d[v_{2}]$且对$u$来说$v2$比$v1$更优:
- $$dp[v_{1}]+(dis[u]-dis[v_{1}])*p[u]+q[u] > dp[v_{2}]+(dis[u]-dis[v_{2}])*p[u]+q[u] ;$$
- $$\frac{dp[v_{2}]-dp[v_{1}]}{dis[v2]-dis[v1]} < p[u]$$
- 可以维护$(dis[v],dp[v])$的下凸包(斜率单调上升);
- 由于是在一颗树上且有$l$的限制,所以我们需要用用一些方法维护一下,
- 可以找树的重心分治,我写的树剖:
- 对每个重链的顶端维护一个凸包,$dfs$的时候不断加入点;
- 我们先$dfs$轻儿子,这样一个点到根的轻链的父亲都是一个凸包的末端;
- 找转移点的时候不断向上跳,如果某条链全部满足限制则在重链顶端的凸包上直接查询;
- 否则一定是合法的分界点在当前找到的链上,用线段树维护区间的凸包查询即可;
- 一次最多找到$log$条树链,最多有一条树链需要在线段树里面查询;
- 算上三分,时间复杂度:$O(nlog^2n)$
- 有个小技巧,线段树满了之后再做凸包
#include<bits/stdc++.h>
#define ls (k<<1)
#define rs (k<<1|1)
#define ll long long
#define ld double
using namespace std;
const int N=;
char gc(){
static char*p1,*p2,s[];
if(p1==p2)p2=(p1=s)+fread(s,,,stdin);
return(p1==p2)?EOF:*p1++;
}
ll rd(){
ll x=; char c=gc();
while(c<''||c>'')c=gc();
while(c>=''&&c<='')x=(x<<)+(x<<)+c-'',c=gc();
return x;
}
int n,T,f[N],o=,hd[N],dep[N],fa[N][],bin[];
int idx,sz[N],tp[N],sn[N],mx[N],id[N],cnt[N<<],st[N];
ll dp[N],tmp,dis[N],s[N],p[N],q[N],l[N];
struct Poi{
ld x,y;
Poi(ld _x=,ld _y=):x(_x),y(_y){};
Poi operator -(const Poi&a){return Poi(x-a.x,y-a.y);}
ld operator ^(const Poi&a){return x*a.y-y*a.x;}
bool operator <(const Poi&a){return x==a.x?y<a.y:x<a.x;}
}P[N];
vector<int>g1[N<<],g2[N];
struct Edge{int v,nt;}E[N];
void adde(int u,int v){E[o]=(Edge){v,hd[u]};hd[u]=o++;}
void dfs1(int u){
sz[u]=;
fa[u][]=f[u];
dep[u]=dep[f[u]]+;
dis[u]=dis[f[u]]+s[u];
for(int i=;bin[i]<dep[u];++i)fa[u][i]=fa[fa[u][i-]][i-];
for(int i=hd[u];i;i=E[i].nt){
int v=E[i].v;
dfs1(v);
sz[u]+=sz[v];
if(sz[v]>sz[sn[u]])sn[u]=v;
}
}
void dfs2(int u,int t){
tp[u]=t;
id[u]=++idx;
st[idx]=u;
if(sn[u])dfs2(sn[u],t);
for(int i=hd[u];i;i=E[i].nt){
int v=E[i].v;
if(v==sn[u])continue;
dfs2(v,v);
}
}
inline bool judge(int a,int b,int c){return ((P[b]-P[a])^(P[c]-P[b]))<=;}
void pushup(int k){
int l=ls,r=rs,tl=,tr=;
while(tl<(int)g1[l].size()||tr<(int)g1[r].size()){
if(tr==(int)g1[r].size()||(tl<(int)g1[l].size()&&g1[l][tl]<g1[r][tr])){
while(g1[k].size()>&&judge(g1[k][g1[k].size()-],g1[k].back(),g1[l][tl]))g1[k].pop_back();
g1[k].push_back(g1[l][tl++]);
}else{
while(g1[k].size()>&&judge(g1[k][g1[k].size()-],g1[k].back(),g1[r][tr]))g1[k].pop_back();
g1[k].push_back(g1[r][tr++]);
}
}
}
void ins1(int k,int l,int r,int u){
cnt[k]++;
if(l==r){g1[k].push_back(u);return;}
int mid=(l+r)>>;
if(id[u]<=mid)ins1(ls,l,mid,u);
else ins1(rs,mid+,r,u);
if(tp[st[l]]==tp[st[r]]&&cnt[k]==r-l+)pushup(k);
}
void ins2(int k,int u){
while(g2[k].size()>&&judge(g2[k][g2[k].size()-],g2[k].back(),u))g2[k].pop_back();
g2[k].push_back(u);
}
inline bool ok(int u,int v){return dis[u]-dis[v]<=l[u];}
inline void upd(ll&x,ll y){if(x>y)x=y;}
void cal(vector<int>&g,int u){
int l=,r=g.size()-;
while(r-l>){
int mid=(r-l)/,mid1=l+mid,mid2=r-mid;
ll t1=dp[g[mid1]]-dis[g[mid1]]*p[u];
ll t2=dp[g[mid2]]-dis[g[mid2]]*p[u];
if(t1>t2)l=mid1+;
else r=mid2-;
}
for(int i=l;i<=r;++i)upd(tmp,dp[g[i]]-dis[g[i]]*p[u]);
}
void query1(int k,int l,int r,int x,int y,int u){
if(l==x&&r==y){cal(g1[k],u);return;}
int mid=(l+r)>>;
if(y<=mid)query1(ls,l,mid,x,y,u);
else if(x>mid)query1(rs,mid+,r,x,y,u);
else query1(ls,l,mid,x,mid,u),query1(rs,mid+,r,mid+,y,u);
}
void query2(int x,int u){
cal(g2[x],u);
}
void solve(int u){
tmp=u==?:9e18;
for(int x=f[u],t=tp[x];x;x=f[t],t=tp[x]){
if(dep[mx[u]]<dep[t])query2(id[t],u);
else {query1(,,n,id[mx[u]],id[x],u);break;}
}
dp[u]=dis[u]*p[u]+q[u]+tmp;
P[u]=Poi(dis[u],dp[u]);
ins1(,,n,u);
ins2(id[tp[u]],u);
}
void calmx(int u){
int t=u;
for(int i=;~i;--i)if(fa[t][i]&&ok(u,fa[t][i]))t=fa[t][i];
mx[u]=t;
}
void dfs3(int u){
calmx(u);
solve(u);
for(int i=hd[u];i;i=E[i].nt){
int v=E[i].v;
if(v==sn[u])continue;
dfs3(v);
}
if(sn[u])dfs3(sn[u]);
}
int main(){
#ifndef ONLINE_JUDGE
freopen("bzoj3672.in","r",stdin);
freopen("bzoj3672.out","w",stdout);
#endif
for(int i=bin[]=;i<=;++i)bin[i]=bin[i-]<<;
n=rd();T=rd();
for(int i=;i<=n;++i){
adde(f[i]=rd(),i);
s[i]=rd();p[i]=rd();
q[i]=rd();l[i]=rd();
}
dfs1();
dfs2(,);
dfs3();
for(int i=;i<=n;++i)printf("%lld\n",dp[i]);
return ;
}
bzoj3672【NOI2014】购票的更多相关文章
- bzoj千题计划251:bzoj3672: [Noi2014]购票
http://www.lydsy.com/JudgeOnline/problem.php?id=3672 法一:线段树维护可持久化单调队列维护凸包 斜率优化DP 设dp[i] 表示i号点到根节点的最少 ...
- [BZOJ3672][Noi2014]购票 斜率优化+点分治+cdq分治
3672: [Noi2014]购票 Time Limit: 30 Sec Memory Limit: 512 MBSubmit: 1749 Solved: 885[Submit][Status][ ...
- BZOJ3672: [Noi2014]购票【CDQ分治】【点分治】【斜率优化DP】
Description 今年夏天,NOI在SZ市迎来了她30周岁的生日.来自全国 n 个城市的OIer们都会从各地出发,到SZ市参加这次盛会. 全国的城市构成了一棵以SZ市为根的有根树,每个城市与它的 ...
- BZOJ3672 [Noi2014]购票 【点分治 + 斜率优化】
题目链接 BZOJ3672 题解 如果暂时不管\(l[i]\)的限制,并假使这是一条链 设\(f[i]\)表示\(i\)节点的最优答案,我们容易得到\(dp\)方程 \[f[i] = min\{f[j ...
- BZOJ3672: [Noi2014]购票(CDQ分治,点分治)
Description 今年夏天,NOI在SZ市迎来了她30周岁的生日.来自全国 n 个城市的OIer们都会从各地出发,到SZ市参加这次盛会. 全国的城市构成了一棵以SZ市为根的有根树 ...
- BZOJ3672 : [Noi2014]购票
设d[i]表示i到1的距离 f[i]=w[i]+min(f[j]+(d[i]-d[j])*v[i])=w[i]+d[i]*v[i]+min(-d[j]*v[i]+f[j]) 对这棵树进行点分治,每次递 ...
- BZOJ3672: [Noi2014]购票(dp 斜率优化 点分治 二分 凸包)
题意 题目链接 Sol 介绍一种神奇的点分治的做法 啥?这都有根树了怎么点分治?? 嘿嘿,这道题的点分治不同于一般的点分治.正常的点分治思路大概是先统计过重心的,再递归下去 实际上一般的点分治与统计顺 ...
- bzoj3672: [Noi2014]购票(树形DP+斜率优化+可持久化凸包)
这题的加强版,多了一个$l_i$的限制,少了一个$p_i$的单调性,难了好多... 首先有方程$f(i)=min\{f(j)+(dep_i-dep_j)*p_i+q_i\}$ $\frac {f(j) ...
- [BZOJ3672][UOJ#7][NOI2014]购票
[BZOJ3672][UOJ#7][NOI2014]购票 试题描述 今年夏天,NOI在SZ市迎来了她30周岁的生日.来自全国 n 个城市的OIer们都会从各地出发,到SZ市参加这次盛会. ...
- 【BZOJ3672】[Noi2014]购票 树分治+斜率优化
[BZOJ3672][Noi2014]购票 Description 今年夏天,NOI在SZ市迎来了她30周岁的生日.来自全国 n 个城市的OIer们都会从各地出发,到SZ市参加这次盛会. ...
随机推荐
- 关于Maven的一点理解
maven是一个项目管理工具,主要作用是: 1.依赖管理(jar包,工程之间); 2.统一开发规范和工具.完成项目的一步构建 3.工程聚合.继承.依赖 其核心配置文件就是pom.xml:pom即Pro ...
- can总线实现stm32的IAP
使用stm32f105rct6的can通信做IAP,实现固件的远程更新功能.IAP的实现包括两个程序:BootLoader和应用程序.启动过程先启动BootLoader,等待1s,若接收到烧写指令则开 ...
- LeetCode 461. Hamming Distance (C++)
题目: The Hamming distance between two integers is the number of positions at which the corresponding ...
- Daily Scrum 11.18
今日完成任务: 1.在提问问题的时候为问题创建索引 2.解决了修改个人资料后刷新没有更新的问题 3.初步加入了采纳功能(没完善UI设计) 遇到困难:创建索引之后,跳转到主页,需要重新登录,找了半天不知 ...
- 2017-2018-2 1723 『Java程序设计』课程 结对编程练习-四则运算-准备阶段
2017-2018-2 1723 『Java程序设计』课程 结对编程练习-四则运算-准备阶段 在一个人孤身奋斗了将近半个学期以后,终于迎来的我们的第一次团队协作共同编码,也就是,我们的第一个结对编程练 ...
- Task2 四则运算2
1.任务要求:对之前的自动出题系统提出了新的要求:(1).题目避免重复:(2).可定制(数量/打印方式):(3)可以控制下列参数:是否有乘除法.数值范围.加减有无负数.除法有无余数.是否支持分数... ...
- TCP/IP,HTTP,HTTPS,WEBSocket协议
我看看着挺多的,我暂时没时间自己写,有需要的请借鉴 http://mp.weixin.qq.com/s?__biz=MzI0MDQ4MTM5NQ==&mid=2247486927&id ...
- 软工1816 · Beta冲刺(2/7)
团队信息 队名:爸爸饿了 组长博客:here 作业博客:here 组员情况 组员1(组长):王彬 过去两天完成了哪些任务 完成考试 确定历史记录页面与排行榜页面的前端页面风格 接下来的计划 & ...
- 第三次作业---excel导入数据库及显示(2)
发现第一次做的功能有点复杂,不能理解.而且第一次的想法是在页面上上传文件,连接并导入到数据库,并在页面上显示.后来才看到要求是直接在本地将数据导入数据库就行了,然后显示.所以才出现了一堆看不懂也解决不 ...
- 《TCP/IP 详解 卷1:协议》第 9 章:广播和本地组播(IGMP 和 MLD)
我已经懒了,卷一已经是去年年底看完的,但怎么说卷一的坑开了就要填完啊-- 广播和本地组播(IGMP 和 MLD) 引言 有 4 种 IP 地址,单播(unicast).任播(anycast).组播(m ...