Description

今年夏天,NOI在SZ市迎来了她30周岁的生日。来自全国 n 个城市的OIer们都会从各地出发,到SZ市参加这次盛会。

全国的城市构成了一棵以SZ市为根的有根树,每个城市与它的父亲用道路连接。为了方便起见,我们将全国的 n 个城市用 1 到 n 的整数编号。其中SZ市的编号为 1。对于除SZ市之外的任意一个城市 v,我们给出了它在这棵树上的父亲城市 fv 以及到父亲城市道路的长度 sv。

从城市 v 前往SZ市的方法为:选择城市 v 的一个祖先 a,支付购票的费用,乘坐交通工具到达 a。再选择城市 a 的一个祖先 b,支付费用并到达 b。以此类推,直至到达SZ市。

对于任意一个城市 v,我们会给出一个交通工具的距离限制 lv。对于城市 v 的祖先 a,只有当它们之间所有道路的总长度不超过 lv 时,从城市 v 才可以通过一次购票到达城市 a,否则不能通过一次购票到达。对于每个城市 v,我们还会给出两个非负整数 pv,qv 作为票价参数。若城市 v 到城市 a 所有道路的总长度为 d,那么从城市 v 到城市 a 购买的票价为 dpv+qv。

每个城市的OIer都希望自己到达SZ市时,用于购票的总资金最少。你的任务就是,告诉每个城市的OIer他们所花的最少资金是多少。

Solution

这题坑死我了

正解:斜率优化DP

容易推出 \(f[i]=f[v]+(dis[i]-dis[v])*p[i]+q[i]\) \(v\)为某个祖先

化成斜率优化的形式:\(f[v]=dis[v]*p[i]+f[i]-q[i]-dis[i]*p[i]\)

所以相当于使用 \(k=p[i],b=f[i]-q[i]+dis[i]*p[i]\) 的直线去割若干个点 \((dis[v],f[v])\)

因为转移是在父子之间的,所以可以分治.

1.首先递归父亲所在块

2.用父亲所在的块更新所有儿子所在的块

3.递归处理所有的儿子

更新的方式大致是:

儿子按 \(dis[i]-l[i]\) 排序,把符合要求的点加入,维护凸包(然而大佬们都是半平面交),三分合适的斜率.

口胡完了,实现也比较简单

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=200005;
int TT,head[N],num=0,nxt[N<<1],to[N<<1];ll c[N<<1];
ll dis[N],p[N],q[N],lim[N],inf;int n,fa[N];bool vis[N];
inline void link(int x,int y,ll z){
nxt[++num]=head[x];to[num]=y;c[num]=z;head[x]=num;
}
int sz[N],son[N]={N},sum,rt;
inline void getroot(int x,int last){
sz[x]=1;son[x]=0;
for(int i=head[x];i;i=nxt[i]){
int u=to[i];
if(vis[u] || u==last)continue;
getroot(u,x);
sz[x]+=sz[u];son[x]=max(son[x],sz[u]);
}
son[x]=max(son[x],sum-sz[x]);
if(son[x]<son[rt])rt=x;
}
inline void priwork(int x,int last){
for(int i=head[x];i;i=nxt[i]){
int u=to[i];
if(u==last)continue;
dis[u]=dis[x]+c[i];fa[u]=x;
priwork(u,x);
}
}
int Q[N],cnt=0,pre[N],a[N],tot=0,st[N];ll f[N];
inline void bfs(int S){
int t=0;cnt=0;
Q[++cnt]=S;pre[S]=fa[S];
while(t!=cnt){
int x=Q[++t];
for(int i=head[x];i;i=nxt[i]){
if(to[i]==pre[x] || vis[to[i]])continue;
Q[++cnt]=to[i];pre[to[i]]=x;
}
}
for(int i=1;i<=cnt;i++)pre[Q[i]]=0;
}
inline void dfs(int x,int root){
if(!x)return ;
a[++tot]=x;
if(x==root)return ;
if(fa[x])dfs(fa[x],root);
}
inline bool comp(int i,int j){
if(dis[i]!=dis[j])return dis[i]>dis[j];
return f[i]<f[j];
}
inline bool compdis(int i,int j){
return dis[i]-lim[i]>dis[j]-lim[j];
}
inline void calc(int x,int root){
bfs(x);
tot=0;dfs(fa[x],root);
sort(a+1,a+tot+1,comp);
sort(Q+1,Q+cnt+1,compdis);
int top=0,r=1;
for(int i=1;i<=cnt;i++){
int x=Q[i];
while(r<=tot && dis[x]-lim[x]<=dis[a[r]]){
while(top>=2 &&
(f[a[r]]-f[st[top]])/(dis[a[r]]-dis[st[top]])>
(f[st[top]]-f[st[top-1]])/(dis[st[top]]-dis[st[top-1]]))top--;
st[++top]=a[r++];
}
int L=1,R=top,mid,ret=top,ml,mr;
while(L<=R){
mid=(L+R)>>1;
ml=(L+mid)>>1;mr=(mid+1+R)>>1;
if(f[st[ml]]-dis[st[ml]]*p[x]<=f[st[mr]]-dis[st[mr]]*p[x])ret=ml,R=mr-1;
else ret=mr,L=ml+1;
}
f[x]=min(f[x],f[st[ret]]+(dis[x]-dis[st[ret]])*p[x]+q[x]);
}
}
inline void solve(int x,int root){
vis[x]=1;
if(fa[x] && !vis[fa[x]])
rt=0,sum=sz[fa[x]],getroot(fa[x],x),solve(rt,root);
calc(x,root);
for(int i=head[x];i;i=nxt[i]){
if(vis[to[i]] || to[i]==fa[x])continue;
rt=0;sum=sz[to[i]];getroot(to[i],x);solve(rt,x);
}
}
void work()
{
int x;ll y;
scanf("%d%d",&n,&TT);
for(int i=2;i<=n;i++){
scanf("%d%lld%lld%lld%lld",&x,&y,&p[i],&q[i],&lim[i]);
link(x,i,y);link(i,x,y);
}
memset(f,127/3,sizeof(f));f[1]=0;inf=f[0];
priwork(1,1);getroot(1,1);
solve(1,1);
for(int i=2;i<=n;i++)printf("%lld\n",f[i]);
}
int main()
{
freopen("pp.in","r",stdin);
freopen("pp.out","w",stdout);
work();
return 0;
}

bzoj 3672: [Noi2014]购票的更多相关文章

  1. BZOJ 3672[NOI2014]购票(树链剖分+线段树维护凸包+斜率优化) + BZOJ 2402 陶陶的难题II (树链剖分+线段树维护凸包+分数规划+斜率优化)

    前言 刚开始看着两道题感觉头皮发麻,后来看看题解,发现挺好理解,只是代码有点长. BZOJ 3672[NOI2014]购票 中文题面,题意略: BZOJ 3672[NOI2014]购票 设f(i)f( ...

  2. bzoj 3672: [Noi2014]购票 树链剖分+维护凸包

    3672: [Noi2014]购票 Time Limit: 30 Sec  Memory Limit: 512 MBSubmit: 480  Solved: 212[Submit][Status][D ...

  3. BZOJ 3672: [Noi2014]购票( 树链剖分 + 线段树 + 凸包 )

    s弄成前缀和(到根), dp(i) = min(dp(j) + (s(i)-s(j))*p(i)+q(i)). 链的情况大家都会做...就是用栈维护个下凸包, 插入时暴力弹栈, 查询时就在凸包上二分/ ...

  4. ●BZOJ 3672 [Noi2014]购票

    题链: http://www.lydsy.com/JudgeOnline/problem.php?id=3672 题解: 斜率优化DP,点分治(树上CDQ分治...) 这里有一个没有距离限制的简单版: ...

  5. BZOJ 3672 [Noi2014]购票 (熟练剖分+凸壳维护)

    题目链接:http://www.lydsy.com:808/JudgeOnline/problem.php?id=3672 题意:给出一棵有根树(1为根),边有长度.每个点u有三个属性(len[u], ...

  6. BZOJ 3672 [NOI2014]购票 (凸优化+树剖/树分治)

    题目大意: 略 题面传送门 怎么看也是一道$duliu$题= = 先推式子,设$dp[x]$表示到达$x$点到达1节点的最小花费 设$y$是$x$的一个祖先,则$dp[x]=min(dp[y]+(di ...

  7. BZOJ 3672: [Noi2014]购票 树上CDQ分治

    做这道题真的是涨姿势了,一般的CDQ分治都是在序列上进行的,这次是把CDQ分治放树上跑了~ 考虑一半的 CDQ 分治怎么进行: 递归处理左区间,处理左区间对右区间的影响,然后再递归处理右区间. 所以, ...

  8. 【BZOJ 3672】 3672: [Noi2014]购票 (CDQ分治+点分治+斜率优化)**

    3672: [Noi2014]购票 Description  今年夏天,NOI在SZ市迎来了她30周岁的生日.来自全国 n 个城市的OIer们都会从各地出发,到SZ市参加这次盛会.        全国 ...

  9. bzoj千题计划251:bzoj3672: [Noi2014]购票

    http://www.lydsy.com/JudgeOnline/problem.php?id=3672 法一:线段树维护可持久化单调队列维护凸包 斜率优化DP 设dp[i] 表示i号点到根节点的最少 ...

随机推荐

  1. 微信APP简要分析

    Part1 走进微信APP 很明显,微信是很成功的APP. 微信 (WeChat) 是腾讯公司于2011年1月21日推出的一个为智能终端提供即时通讯服务的免费应用程序,现已是超过九亿人使用的手机应用. ...

  2. Alpha第九天

    Alpha第九天 听说 031502543 周龙荣(队长) 031502615 李家鹏 031502632 伍晨薇 031502637 张柽 031502639 郑秦 1.前言 任务分配是VV.ZQ. ...

  3. Alpha冲刺No.4

    冲刺Day4 一.站立式会议 本来还想今天下午好好弄弄安卓开发,结果计划赶不上变化.(不存在的) 完成备忘录设计,个人界面设计 二.实际项目进展 搞了404(安卓和ssm的连接),好像还是不太行. 备 ...

  4. 201621123062《java程序设计》第13周作业总结

    1. 本周学习总结 以你喜欢的方式(思维导图.OneNote或其他)归纳总结多网络相关内容. 思维导图: 2. 为你的系统增加网络功能(购物车.图书馆管理.斗地主等)-分组完成 为了让你的系统可以被多 ...

  5. 20162330 实验二 《Java面向对象程序设计》 实验报告

    2016-2017-2 实验报告目录: 1 2 3 4 5 20162330 实验二 <Java面向对象程序设计> 实验报告 课程名称:<程序设计与数据结构> 学生班级:162 ...

  6. python网络爬虫,知识储备,简单爬虫的必知必会,【核心】

    知识储备,简单爬虫的必知必会,[核心] 一.实验说明 1. 环境登录 无需密码自动登录,系统用户名shiyanlou 2. 环境介绍 本实验环境采用带桌面的Ubuntu Linux环境,实验中会用到桌 ...

  7. python 异步协程

    """A very simple co-routine scheduler. Note: this is written to favour simple code ov ...

  8. var、let、const区别

    1.let不存在变量提升,必须升明后才可用. 'use strict'; (function(){ console.log(varTest); console.log(letTest); var va ...

  9. JAVA_SE基础——38.单例设计模式

    本文继续介绍23种设计模式系列之单例模式. 我们在javaSE的基础学习中,会讲到:单例设计模式.模板设计模式.装饰者设计模式.观察者设计模式.工厂设计模式 我以后随着水平的提高,我会专门开个分类写设 ...

  10. thinkphp框架的大D方法应用

    大D方法中需要传递一个模型,比如UserModer,就传递D('User'),而数据库中存在一个表比如think_user,其中think就是前缀. 在UserModel里面存在自动验证.自动完成可以 ...