[NOI2014] 购票

NOI2014 购票 - 洛谷 P2305

标签 斜率优化,线段树,分治

先考虑序列上的情况,令 \(f_u\) 表示从 \(u\)\(1\) 的最小代价。

下面的 \(s\) 是题目中 \(s\)前缀和,前缀和对于每个 \(u\),都可以二分找到一个 \(L\),使得 \(L\) 是最小的 \(s_u - s_{L - 1} \le l_u\),那么 \(f_u = \min\limits_{v = L}^{u - 1} \{ f_v + (s_u - s_{L - 1})p_u \} + q_u\),显然是一个斜率优化的形式。因为是从区间转移过来,可以使用分治/线段树套单调栈的做法。还有一点: \(p_u\) 不单调,需要使用二分。


现在丢到树上,我们可以想办法往序列上靠。这里介绍两种方法。(题解有 \(4\) 种)

\(s\) 变成了 \(u\)\(1\) 的边权之和。

F1

序列上可以分治,在树上自然可以点分治

特别的一点是,这时一棵有根树。找到点分中心后,就用 \(1\) 所在的那棵子树对剩下的部分进行转移,按照 \(s\) 排序后后,双指针转移即可。

时间复杂度:\(O(n\log^2n)\)

F2

首先有十分暴力的做法:树链剖分,但这玩意就 \(3\log\) 了,听说也能搞过。但是我们还要寻找一个更加优秀的方式,将树转化为序列。

这里有一个十分神奇的 trick:使用 出栈序

具体的,我们按照离开 \(u\) 子树的时间对 \(u\) 进行排序,设 \(u\) 的排名为 \(rnk_u\)。DFS 求解 \(f_u\) 时,仍然可以倍增求出那个最浅的 \(L\)\(L\)\(u\) 的祖先),那么直接从区间 \([rnk_u, rnk_L]\) 转移过来即可。

证明如下: 区间内的点 \(v\) 分为两类

  • \(v\)\(u\) 的祖先,那么本来就可以转移到 \(u\)
  • 否则 \(v\) 此时肯定还没有被访问到(\(rnk_v > rnk_u\)),转移过来就是没转移。

于是沿用序列的做法即可。

时间复杂度:\(O(n \log^2 n)\)

可能你会有疑问:用线段树套单调栈,直接加入,\(d\) 有单调性吗?答案是没有,但是你查询的时候有就行了。或者你可以写李超树。

总结

序列问题还是比较好解决的,就是要想尽办法变成树上问题。这题有一个出栈序的神秘 trick 可以轻松解决这个问题。

posted @ 2025-12-11 20:35  xiehanrui0817  阅读(3)  评论(0)    收藏  举报