LOJ 2249: 洛谷 P2305: 「NOI2014」购票
题目传送门:LOJ #2249。
题意简述:
有一棵以 \(1\) 号节点为根节点的带边权的树。
除了 \(1\) 号节点的所有节点上都有人需要坐车到达 \(1\) 号节点。
除了 \(1\) 号节点,每个节点都有 \(5\) 个参数 \(f_u,s_u,p_u,q_u,l_u\)。
\(f_u\) 表示 \(u\) 号点的父亲,\(s_u\) 表示 \(u\) 号点与父亲之间的边的权值,\(p,q,l\) 为车票参数。
定义两个节点 \(u\) 和 \(v\) 之间的距离 \(dis_{u,v}\) 为 \(u\) 和 \(v\) 在树上的简单路径上的边权之和。
从一个节点 \(u\),可以坐车到达节点 \(v\) 当且仅当 \(dis_{u,v}\le l_u\),且需要花费 \(dis_{u,v}\times p_u+q_u\) 的代价。
问除了 \(1\) 号节点的每个节点坐车到 \(1\) 号节点需要花费的最小总代价。
\(1\le n\le 2\times 10^5\),保证输入的所有数都是非负整数,\(l_u\ge s_u\),保证答案在 long long 范围内。
题解:
考虑树形 DP,令 \(\mathrm{f}[u]\) 为 \(u\) 到 \(1\) 的最小总代价,\(\mathrm{dis}[u]\) 为 \(1\) 号节点到 \(u\) 号节点的距离。
则有 \(\mathrm{f}[u]=\min\limits_{\substack{v\in anc_u\\\mathrm{dis}[u]-\mathrm{dis}[v]\le l_u}}(\mathrm{f}[v]+(\mathrm{dis}[u]-\mathrm{dis}[v])\times p_u+q_u)\)。
令 \(b_u=\mathrm{dis}[u]\times p_u+q_u\),则有:
\]
观察式子,发现 \(v\) 必须是紧接着 \(u\) 往上一段连续的祖先,而转移的方式是简单的加权值取 \(\min\)。
这提示我们考虑斜率优化,考虑两个合法转移点 \(j\) 和 \(k\),比较 \(j\) 和 \(k\) 转移的优劣:
\]
发现已经有了斜率的表达式,\(x\) 坐标是 \(\mathrm{dis}\),\(y\) 坐标是 \(\mathrm{f}\)。假设 \(\mathrm{dis}[j]<\mathrm{dis}[k]\),则决策 \(j\) 比 \(k\) 优当且仅当:
\]
即点 \((\mathrm{dis}[j],\mathrm{f}[j])\) 和点 \((\mathrm{dis}[k],\mathrm{f}[k])\) 之间的线段的斜率大于 \(p_u\)。
所以我们需要用单调栈维护一个合法点的下凸壳,这样可以根据不同的 \(p_u\) 在凸壳上二分得到决策点。
但是这样有一个问题,我们知道合法的决策点是 \(u\) 的近几层祖先,即 \(u\) 到祖先的链上 \(\mathrm{dis}\) 较大的节点,它们对应的点也是靠右的。

考虑这张图,假设 A 点是非法转移点,而 B、C、D 都是合法转移点,此时维护的凸壳并不包含 B,然而 B 可能是最优决策点。
也就是说,我们需要考虑一段后缀中的最优转移点,然而我们又不能维护所有后缀的凸壳,应该怎么办呢?
有一个解决方法:维护一些区间中的凸壳,查询时选择一些区间的并恰好等于需要的后缀,在每个区间内分别查询最优决策并更新。
这提示我们使用树状数组维护后缀信息,也就是树状数组套单调栈。
这样花费的空间是 \(\Theta(n\log n)\) 的,修改时间 \(\mathcal{O}(\log n)\),查询时间 \(\mathcal{O}(\log^2 n)\)。
还有最后一个问题,需要处理的不是序列上而是树上的转移,这并不难实现,我们维护可撤销单调栈,在回溯的时候撤销这次操作即可。
关于可撤销单调栈,考虑单调栈的每一次操作只会更改栈顶指针以及栈顶位置的值,我们维护历史每一次操作原先的栈顶指针以及栈顶位置原来的值即可实现撤销操作,这样插入和撤销均是 \(\Theta(1)\) 的。
#include <cstdio>
#include <vector>
#include <algorithm>
typedef long long LL;
const int MN = 200005;
const int MS = 2100005;
const LL Inf = 0x7fffffffffffffff;
int N, faz[MN];
std::vector<int> G[MN];
LL wgh[MN], dep[MN], dis[MN], p[MN], q[MN], b[MN], len[MN];
LL stds[MN], tds;
LL f[MN], *X = dis, *Y = f;
inline double Slope(int i, int j) {
return X[i] == X[j] ? 1e60 : (double)(Y[j] - Y[i]) / (X[j] - X[i]);
}
int stkp[MS], valp[MS], tpp[MS];
int *istk[MN], *ival[MN], *itp[MN], it[MN];
inline void Push(int id, int u) {
int t = it[id], tp = itp[id][t], *stk = istk[id];
while (tp > 0 && Slope(stk[tp - 1], stk[tp]) >= Slope(stk[tp], u)) --tp;
++t, ival[id][t] = stk[itp[id][t] = ++tp], stk[tp] = u, it[id] = t;
}
inline void Pop(int id) {
istk[id][itp[id][it[id]]] = ival[id][it[id]];
--it[id];
}
inline int chk(int id, LL slp) {
int t = it[id], tp = itp[id][t], *stk = istk[id];
if (!~tp) return -1;
int lb = 0, rb = tp - 1, x = tp, mid;
while (lb <= rb) {
mid = (lb + rb) >> 1;
if (Slope(stk[mid], stk[mid + 1]) <= slp) lb = mid + 1;
else x = mid, rb = mid - 1;
}
return stk[x];
}
inline void PushAll(int i, int u) { for (; i <= N; i += i & -i) Push(i, u); }
inline void PopAll(int i) { for (; i <= N; i += i & -i) Pop(i); }
inline void GetDp(int u) {
f[u] = Inf;
int i = std::lower_bound(stds + 1, stds + tds + 1, dis[u] - len[u]) - stds;
for (i = N - i + 1; i; i -= i & -i) {
int v = chk(i, p[u]);
if (~v) f[u] = std::min(f[u], f[v] - dis[v] * p[u] + b[u]);
}
}
void DFS(int u) {
dep[u] = dep[faz[u]] + 1;
dis[u] = dis[faz[u]] + wgh[u];
stds[++tds] = dis[u];
b[u] = dis[u] * p[u] + q[u];
GetDp(u);
PushAll(N - dep[u], u);
for (auto v : G[u]) DFS(v);
PopAll(N - dep[u]);
--tds;
}
int main() {
scanf("%d%*d", &N);
istk[1] = stkp, itp[1] = tpp, ival[1] = valp, itp[1][it[1] = 0] = -1;
for (int i = 2; i <= N; ++i) {
int lenl = ((i - 1) & (1 - i)) + 1;
istk[i] = istk[i - 1] + lenl;
itp[i] = itp[i - 1] + lenl;
ival[i] = ival[i - 1] + lenl;
itp[i][it[i] = 0] = -1;
}
for (int i = 2; i <= N; ++i) {
scanf("%d%lld%lld%lld%lld", &faz[i], &wgh[i], &p[i], &q[i], &len[i]);
G[faz[i]].push_back(i);
}
PushAll(N, 1), stds[tds = 1] = 0;
for (auto u : G[1]) DFS(u);
for (int i = 2; i <= N; ++i) printf("%lld\n", f[i]);
return 0;
}
LOJ 2249: 洛谷 P2305: 「NOI2014」购票的更多相关文章
- LOJ 2249: 洛谷 P2305: bzoj 3672: 「NOI2014」购票
题目传送门:LOJ #2249. 题意简述: 有一棵以 \(1\) 号节点为根节点的带边权的树. 除了 \(1\) 号节点的所有节点上都有人需要坐车到达 \(1\) 号节点. 除了 \(1\) 号节点 ...
- LOJ#2249 Luogu P2305「NOI2014」购票
几乎肝了半个下午和整个晚上 斜率优化的模型好多啊... LOJ #2249 Luogu P2305 题意 给定一棵树,第$ i$个点如果离某个祖先$ x$的距离不超过$ L_i$,可以花费$ P_i· ...
- LOJ 3045: 洛谷 P5326: 「ZJOI2019」开关
题目传送门:LOJ #3045. 题意简述 略. 题解 从高斯消元出发好像需要一些集合幂级数的知识,就不从这个角度思考了. 令 \(\displaystyle \dot p = \sum_{i = 1 ...
- LOJ 3089: 洛谷 P5319: 「BJOI2019」奥术神杖
题目传送门:LOJ #3089. 题意简述: 有一个长度为 \(n\) 的母串,其中某些位置已固定,另一些位置可以任意填. 同时给定 \(m\) 个小串,第 \(i\) 个为 \(S_i\),所有位置 ...
- LOJ 3093: 洛谷 P5323: 「BJOI2019」光线
题目传送门:LOJ #3093. 题意简述: 有 \(n\) 面玻璃,第 \(i\) 面的透光率为 \(a\),反射率为 \(b\). 问把这 \(n\) 面玻璃按顺序叠在一起后,\(n\) 层玻璃的 ...
- LOJ 3043: 洛谷 P5280: 「ZJOI2019」线段树
题目传送门:LOJ #3043. 题意简述: 你需要模拟线段树的懒标记过程. 初始时有一棵什么标记都没有的 \(n\) 阶线段树. 每次修改会把当前所有的线段树复制一份,然后对于这些线段树实行一次区间 ...
- LOJ 2483: 洛谷 P4655: 「CEOI2017」Building Bridges
题目传送门:LOJ #2483. 题意简述: 有 \(n\) 个数,每个数有高度 \(h_i\) 和价格 \(w_i\) 两个属性. 你可以花费 \(w_i\) 的代价移除第 \(i\) 个数(不能移 ...
- LOJ 2312(洛谷 3733) 「HAOI2017」八纵八横——线段树分治+线性基+bitset
题目:https://loj.ac/problem/2312 https://www.luogu.org/problemnew/show/P3733 原本以为要线段树分治+LCT,查了查发现环上的值直 ...
- 洛谷 P4710 「物理」平抛运动
洛谷 P4710 「物理」平抛运动 洛谷传送门 题目描述 小 F 回到班上,面对自己 28 / 110 的物理,感觉非常凉凉.他准备从最基础的力学学起. 如图,一个可以视为质点的小球在点 A(x_0, ...
随机推荐
- X86主要的几种寻址方式
一.首先 P33: 严格来说有三种寻址方式 与数据有关的寻址方式 与转移指令或过程调用指令有关的寻址方式 与IO指令有关的寻址方式 这篇博客只讲1.2两条 二.然后 1. 与数据有关的寻址方式 数据, ...
- “Linux内核分析”实验三报告
构造一个简单的Linux系统 张文俊+原创作品转载请注明出处+<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-10000290 ...
- Linux内核设计(第一周)——从汇编语言出发理解计算机工作原理
Linux内核设计(第一周)——从汇编语言出发理解计算机工作原理 计算机工作原理 汇编指令 C语言代码汇编分析 by苏正生 原创作品转载请注明出处 <Linux内核分析>MOOC课程htt ...
- 解决p4c安装时protobuf未定义引用的错误
安装好p4c的依赖之后,执行make -j2时出现以下问题: undefined references to `google::protobuf::internal::LogMessage::oper ...
- 第三次spring冲刺1
Not Check Out Check Out Done SPRINT GOAL: BETA-READY RELEASE 困难模式 DONE 修改已知bug DONE 美化界面 ...
- We are a team----sh_6666
团队宣言:编程,我们是玩命的,玩命,我们是认真的. 团队简介: 团队名称:sh_6666队 团队博客链接:http://www.cnblogs.com/sh-6666/ 人物简介: 剧团导演:吴小勇 ...
- JetBrains系列WebStorm等中文输入法无法跟随光标的问题的解决办法
参考:https://blog.csdn.net/wang414300980/article/details/79537875 电脑配置: 解决这个问题的思路就是修改启动软件的JDK,有以下几个方法: ...
- Docker(十二)-Docker Registry镜像管理
Registry删除镜像.垃圾回收 Docker仓库在2.1版本中支持了删除镜像的API,但这个删除操作只会删除镜像元数据,不会删除层数据.在2.4版本中对这一问题进行了解决,增加了一个垃圾回收命令, ...
- 【菜鸟】RESTful 架构详解
RESTful 架构详解 分类 编程技术 1. 什么是REST REST全称是Representational State Transfer,中文意思是表述(编者注:通常译为表征)性状态转移. 它首次 ...
- stacking算法原理及代码
stacking算法原理 1:对于Model1,将训练集D分为k份,对于每一份,用剩余数据集训练模型,然后预测出这一份的结果 2:重复上面步骤,直到每一份都预测出来.得到次级模型的训练集 3:得到k份 ...