题目传送门: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\),则有:

\[\mathrm{f}[u]=b_u+\min\limits_{\substack{v\in anc_u\\\mathrm{dis}[u]-\mathrm{dis}[v]\le l_u}}(\mathrm{f}[v]-\mathrm{dis}[v]\times p_u)
\]

观察式子,发现 \(v\) 必须是紧接着 \(u\) 往上一段连续的祖先,而转移的方式是简单的加权值取 \(\min\)。

这提示我们考虑斜率优化,考虑两个合法转移点 \(j\) 和 \(k\),比较 \(j\) 和 \(k\) 转移的优劣:

\[\begin{aligned}\mathrm{f}[j]-\mathrm{dis}[j]\times p_u&\Leftrightarrow\mathrm{f}[k]-\mathrm{dis}[k]\times p_u\\\mathrm{f}[k]-\mathrm{f}[j]&\Leftrightarrow(\mathrm{dis}[k]-\mathrm{dis}[j])\times p_u\end{aligned}
\]

发现已经有了斜率的表达式,\(x\) 坐标是 \(\mathrm{dis}\),\(y\) 坐标是 \(\mathrm{f}\)。假设 \(\mathrm{dis}[j]<\mathrm{dis}[k]\),则决策 \(j\) 比 \(k\) 优当且仅当:

\[\begin{aligned}\mathrm{f}[j]-\mathrm{dis}[j]\times p_u&<\mathrm{f}[k]-\mathrm{dis}[k]\times p_u\\\mathrm{f}[k]-\mathrm{f}[j]&>(\mathrm{dis}[k]-\mathrm{dis}[j])\times p_u\\\frac{\mathrm{f}[k]-\mathrm{f}[j]}{\mathrm{dis}[k]-\mathrm{dis}[j]}&>p_u\end{aligned}
\]

即点 \((\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: bzoj 3672: 「NOI2014」购票的更多相关文章

  1. LOJ 2567: 洛谷 P3643: bzoj 4584: 「APIO2016」划艇

    题目传送门:LOJ #2249. 题意简述: 有 \(n\) 个位置,第 \(i\) 个位置可以填在 \([a_i,b_i]\) (\(1\le a_i\le b_i\le 10^9\))之间的整数, ...

  2. LOJ 2085: 洛谷 P1587: bzoj 4652: 「NOI2016」循环之美

    题目传送门:LOJ #2085. 两个月之前做的傻题,还是有必要补一下博客. 题意简述: 求分子为不超过 \(n\) 的正整数,分母为不超过 \(m\) 的正整数的所有互不相等的分数中,有多少在 \( ...

  3. LOJ 2249: 洛谷 P2305: 「NOI2014」购票

    题目传送门:LOJ #2249. 题意简述: 有一棵以 \(1\) 号节点为根节点的带边权的树. 除了 \(1\) 号节点的所有节点上都有人需要坐车到达 \(1\) 号节点. 除了 \(1\) 号节点 ...

  4. 「NOI2014」购票 解题报告

    「NOI2014」购票 写完了后发现写的做法是假的...然后居然过了,然后就懒得管正解了. 发现需要维护凸包,动态加点,询问区间,强制在线 可以二进制分组搞,然后你发现在树上需要资瓷撤回,然后暴力撤回 ...

  5. 「NOI2014」购票

    「NOI2014」购票 解题思路 先列出 \(dp\) 式子并稍微转化一下 \[ dp[u] =\min(dp[v]+(dis[u]-dis[v]) \times p[u] + q[u])) \ \ ...

  6. LOJ#2249 Luogu P2305「NOI2014」购票

    几乎肝了半个下午和整个晚上 斜率优化的模型好多啊... LOJ #2249 Luogu P2305 题意 给定一棵树,第$ i$个点如果离某个祖先$ x$的距离不超过$ L_i$,可以花费$ P_i· ...

  7. 洛谷 8 月月赛 & 「PMOI」Round · 04

    T1 T166167 「PMOI-4」人赢 题目大意 给一个数列的前两项分别为\(n\)和\(m\) 当\(i\geq3\)时\(a_i = a_{i-1}*a_{i-2}\)的个位 给定\(n\), ...

  8. LOJ 2743(洛谷 4365) 「九省联考 2018」秘密袭击——整体DP+插值思想

    题目:https://loj.ac/problem/2473 https://www.luogu.org/problemnew/show/P4365 参考:https://blog.csdn.net/ ...

  9. 洛谷 P5206: bzoj 5475: LOJ 2983: [WC2019] 数树

    一道技巧性非常强的计数题,历年WC出得最好(同时可能是比较简单)的题目之一. 题目传送门:洛谷P5206. 题意简述: 给定 \(n, y\). 一张图有 \(|V| = n\) 个点.对于两棵树 \ ...

随机推荐

  1. [LeetCode] 312. Burst Balloons 打气球游戏

    Given n balloons, indexed from 0 to n-1. Each balloon is painted with a number on it represented by ...

  2. [LeetCode] 137. Single Number II 单独的数字之二

    Given a non-empty array of integers, every element appears three times except for one, which appears ...

  3. github git clone ssh协议 clone超慢解决方案,提高Github Clone速度

    即使进行了fq吧但是git clone ssh协议就是慢 2kb/s你能忍,坚决不能忍. github git clone ssh协议 clone超慢解决方案 151.101.72.249 globa ...

  4. LoadRunner名词解释

    Transactions(用户事务分析):用户事务分析是站在用户角度进行的基础性能分析. 1.Transation Sunmmary(事务综述) 对事务进行综合分析是性能分析的第一步,通过分析测试时间 ...

  5. 【网络知识之六】UDP

    UDP(User Datagram Protocol)用户数据报协议,是一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务. 一.UDP报头UDP报头由4个部分组成,其中两个是可选的(粉红背 ...

  6. Turbo码基本框架

    1. 基本原理 1.1 定义 1.2 分量码设计 2. 编码方法 2.1 交织器的设计 2.2 分量编码器 2.3 删余矩阵及复用 3. 译码方法和算法 3.1 迭代译码 3.2 MAP类算法 3.3 ...

  7. 『Norma 分治』

    Norma Description Input Format 第1行,一个整数N: 第2~n+1行,每行一个整数表示序列a. Output Format 输出答案对10^9取模后的结果. Sample ...

  8. 【08】Jenkins:关于发布

    写在前面的话 Jenkins 对于我们用户而言,可能中间会有不同的需求,比如自动构建,接口测试,代码质量检测.但其实我们的最终目的还是打包上线.当然,各个公司的项目开发语言会不一样,但是总体而言发布方 ...

  9. C# WebBrowser控件 下载文件不弹下载提示框的办法

    参考链接 https://stackoverflow.com/questions/6773866/download-file-and-automatically-save-it-to-folder p ...

  10. 【原创】闲来无事,用Winform写了个简易浏览器

    核心是利用了winform自带的WebBrowser控件,修改了下IE内核的版本,目前还是单线程的,逻辑挺简单的,萌新都能看懂. 废话不多说,上代码,附打包project. 链接:https://pa ...