BZOJ3672/UOJ7 [Noi2014]购票
本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作。
本文作者:ljh2000
作者博客:http://www.cnblogs.com/ljh2000-jump/
转载请注明出处,侵权必究,保留最终解释权!
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
正解:CDQ分治+斜率优化DP+树分治
解题报告:
这道题是三算法合一经典好题...
我们考虑如果是在一个序列上,就是simple的斜率优化裸题了。但是P[i]的变化不随i变化而规律性变化,所以我每次要求的最优斜率是不一样的,维护好下凸包,每次在凸包上二分找到最优值即可。
对于树上的距离限制,我们肯定对于每个点要重建凸包,如果每次重建显然复杂度无法承受,所以我们需要改变节点的处理顺序,使得祖先上的点顺次加入并且不用重构,这很简单,只要考虑每个点能被最上面的哪些点更新到,排个序就可以扫一遍做完了。
另外树分治是为了保证我整体上的处理复杂度是log次,CDQ分治的最大精髓就是先递归处理一部分,再用处理完的部分来更新未处理的部分,显然当祖先节点递归处理完之后,就可以用来处理子树,而每棵子树内部的点都共用了一条链上的祖先,更新答案,最后再递归处理就可以了。
说的有点抽象,看看代码理解起来还是挺快的。其实是我懒,不想写公式...
//It is made by ljh2000
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long LL;
const int MAXN = 200011;
const LL inf = (1LL<<62);
int n,f[MAXN],ecnt,first[MAXN],to[MAXN],next[MAXN],size[MAXN],maxS[MAXN],cnt,dui[MAXN];
LL p[MAXN],q[MAXN],lim[MAXN],dis[MAXN],w[MAXN],dp[MAXN];
bool use[MAXN];
struct node{ LL val; int id; }a[MAXN];
inline bool cmp(node q,node qq){ return q.val>qq.val; }
inline void link(int x,int y,LL z){ next[++ecnt]=first[x]; first[x]=ecnt; to[ecnt]=y; w[ecnt]=z; }
inline LL upd(int i,int j){ return dp[j]+(dis[i]-dis[j])*p[i]+q[i]; }
inline LL K(int x,int y){ return (dp[y]-dp[x])/(dis[y]-dis[x]); }
inline int getint(){
int w=0,q=0; char c=getchar(); while((c<'0'||c>'9') && c!='-') c=getchar();
if(c=='-') q=1,c=getchar(); while (c>='0'&&c<='9') w=w*10+c-'0',c=getchar(); return q?-w:w;
} inline LL getLL(){
LL w=0; LL q=0; char c=getchar(); while((c<'0'||c>'9') && c!='-') c=getchar();
if(c=='-') q=1,c=getchar(); while (c>='0'&&c<='9') w=w*10+c-'0',c=getchar(); return q?-w:w;
} inline void dfs(int x){//预处理每个节点的dis和size
size[x]=1;
for(int i=first[x];i;i=next[i]) {
dis[to[i]]=dis[x]+w[i];
dfs(to[i]); size[x]+=size[to[i]];
}
} inline void find_root(int x,int S,int &rt){
maxS[x]=0; size[x]=1;
for(int i=first[x];i;i=next[i]) {
int v=to[i]; if(use[v]) continue;
find_root(v,S,rt);
size[x]+=size[v]; maxS[x]=max(maxS[x],size[v]);
}
maxS[x]=max(maxS[x],S-size[x]);
if(maxS[x]<maxS[rt] && size[x]>1/*不然会GG!!!*/) rt=x;
} inline void dfs2(int x){
a[++cnt].id=x; a[cnt].val=dis[x]-lim[x];
for(int i=first[x];i;i=next[i]) if(!use[to[i]]) dfs2(to[i]);
} inline void solve(int x,int S){
if(S==1) return ; int rt=0,now;
find_root(x,S,rt);
for(int i=first[rt];i;i=next[i]) use[to[i]]=1;//把重心的儿子节点堵上
//CDQ分治
//先处理除了重心的子树之外的部分
solve(x,S-size[rt]+1);//重心也放入这个部分,方便以后讨论 cnt=0; for(int i=first[rt];i;i=next[i]) dfs2(to[i]);
sort(a+1,a+cnt+1,cmp);//把子树内所有点按能被更新到的最高高度自大往小排序
now=rt;//需要向外更新的是,重心到当前分治根节点的这条链上的所有点
int tail,l,r,mid,pos; tail=0;
for(int i=1;i<=cnt;i++) {
while(now!=f[x] && dis[a[i].id]-lim[a[i].id]<=dis[now]) {
while(tail>1 && K(dui[tail],now)>=K(dui[tail-1],dui[tail])) tail--;
//因为dis[now]递减,相当于是横坐标递减,可以看做是倒着加入,注意斜率判断方向
dui[++tail]=now; now=f[now];
}
if(tail>0) {
//在凸包上二分求得最优解
l=1; r=tail; pos=1;
while(l<=r) {
mid=(l+r)>>1; if(mid==tail) { pos=tail; break; }
if(K(dui[mid],dui[mid+1])>=p[a[i].id]) l=mid+1,pos=mid+1;//当前最优的应该是mid+1!!!
else r=mid-1;
}
dp[a[i].id]=min(dp[a[i].id] , upd(a[i].id,dui[pos]));
}
}
for(int i=first[rt];i;i=next[i]) solve(to[i],size[to[i]]);
} inline void work(){
n=getint(); LL x; x=getint();
for(int i=2;i<=n;i++) {
f[i]=getint(); x=getLL(); link(f[i],i,x);
p[i]=getint(); q[i]=getLL(); lim[i]=getLL();
}
dfs(1); maxS[0]=n+1; for(int i=2;i<=n;i++) dp[i]=inf;
solve(1,size[1]);
for(int i=2;i<=n;i++) printf("%lld\n",dp[i]);
} int main()
{
work();
return 0;
}
BZOJ3672/UOJ7 [Noi2014]购票的更多相关文章
- 【BZOJ3672】[Noi2014]购票 树分治+斜率优化
[BZOJ3672][Noi2014]购票 Description 今年夏天,NOI在SZ市迎来了她30周岁的生日.来自全国 n 个城市的OIer们都会从各地出发,到SZ市参加这次盛会. ...
- 【bzoj3672】[Noi2014]购票 斜率优化dp+CDQ分治+树的点分治
题目描述 给出一棵以1为根的带边权有根树,对于每个根节点以外的点$v$,如果它与其某个祖先$a$的距离$d$不超过$l_v$,则可以花费$p_vd+q_v$的代价从$v$到$a$.问从每个点到1花费 ...
- [BZOJ3672][UOJ#7][NOI2014]购票
[BZOJ3672][UOJ#7][NOI2014]购票 试题描述 今年夏天,NOI在SZ市迎来了她30周岁的生日.来自全国 n 个城市的OIer们都会从各地出发,到SZ市参加这次盛会. ...
- 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][ ...
- bzoj 3672: [Noi2014]购票 树链剖分+维护凸包
3672: [Noi2014]购票 Time Limit: 30 Sec Memory Limit: 512 MBSubmit: 480 Solved: 212[Submit][Status][D ...
- BZOJ 3672: [Noi2014]购票( 树链剖分 + 线段树 + 凸包 )
s弄成前缀和(到根), dp(i) = min(dp(j) + (s(i)-s(j))*p(i)+q(i)). 链的情况大家都会做...就是用栈维护个下凸包, 插入时暴力弹栈, 查询时就在凸包上二分/ ...
- [NOI2014]购票 --- 斜率优化 + 树形DP + 数据结构
[NOI2014]购票 题目描述 今年夏天,NOI在SZ市迎来了她30周岁的生日. 来自全国 n 个城市的OIer们都会从各地出发,到SZ市参加这次盛会. 全国的城市构成了一棵以SZ市为根的有根树,每 ...
- 【BZOJ 3672】 3672: [Noi2014]购票 (CDQ分治+点分治+斜率优化)**
3672: [Noi2014]购票 Description 今年夏天,NOI在SZ市迎来了她30周岁的生日.来自全国 n 个城市的OIer们都会从各地出发,到SZ市参加这次盛会. 全国 ...
随机推荐
- [Spring Data MongoDB]学习笔记--MongoTemplate查询操作
查询操作主要用到两个类:Query, Criteria 所有的find方法都需要一个query的object. 1. 直接通过json来查找,不过这种方式在代码中是不推荐的. BasicQuery q ...
- 【BZOJ2819】Nim 树状数组+LCA
[BZOJ2819]Nim Description 著名游戏设计师vfleaking,最近迷上了Nim.普通的Nim游戏为:两个人进行游戏,N堆石子,每回合可以取其中某一堆的任意多个,可以取完,但不可 ...
- 【BZOJ2555】SubString 后缀自动机+LCT
[BZOJ2555]SubString Description 懒得写背景了,给你一个字符串init,要求你支持两个操作 (1):在当前字符串的后面插入一个字符串 (2 ...
- 第三章 T-SQL 编程
3.1 使用变量 变量是可以存储数据值的对象.可以使用局部变量向SQL语句传递数据.在T-SQL中执行一批SQL语句时,可以声明许多变量以便临时使用.声明变量以后,可以在批处理中用一条T-SQL语句设 ...
- bootstrap获取总条目数
$('#table').on('load-success.bs.table', function () {alert($('#table').bootstrapTable('getOptions'). ...
- coursera 《现代操作系统》 -- 第八周 存储模型(2)
名词解释 页面: 页面大小: 页表: 页表项: 以上名词解释见: coursera <现代操作系统> -- 第七周 存储模型(1) 页表项大小: 问:以上是怎么计算出来的? 32位指什么? ...
- Django报:AttributeError: tuple object has no attribute get
def index(request): hero_list=models.HeroInfo.objects.all() return render_to_response('index.html',{ ...
- 关于python代码是编译执行还是解释执行
Python 是编译型语言还是解释型语言?回答这个问题前,应该先弄清楚什么是编译型语言,什么是解释型语言. 所谓编译执行就是源代码经过编译器编译处理,生成目标机器码,就是机器能直接运行的二进制代码,下 ...
- ThreadLocal(四) : FastThreadLocal原理
一.ThreadLocal的原理以及存在的问题 a. 每个线程内部维护了一个ThreadLocal.ThreadLocalMap类型的变量 b. ThreadLocalMap 的 key 为 Thre ...
- kettle连接sqlserver
1.Sql Server的 数据库链接 Sql server链接有两类,MS SQL SERVER 和 MS SQL SERVER(NATIVE),这两个有什么区别呢,且看下面. 第一类,MS SQL ...