《关于本弱智为了减小常数而手动讨论导致写错调到死这件事》
题意简述
有一只蜗牛在树干上爬,有两种移动方式,沿着某根绳子向上爬,或者顺着树干往下溜。
树干高度为 $n$,有 $m$ 根绳子,第 $i$ 条连接了高度 $l_i$ 至 $r_i$,保证 $r_i$ 互不相同。
有 $q$ 次询问,每次给出两个数 $L, R$ ,问蜗牛从高度 $L$ 开始爬,只考虑被包含在 $[L, R]$ 间的绳子(即若一条绳子的区间超出询问范围即不能使用),蜗牛能够爬到的最大高度。
$1 \le n, m, q \le 10^5$ ,输入均为正整数。
主要思路
$O(n\sqrt{n})$ 做法
假设我们要处理右端点为 $R_0$ 的所有询问,则可以将右端点不超过 $R_0$ 的绳子按左端点降序排序,依次插入,用单调栈维护当前被绳子覆盖的区间,在 $O(n)$ 时间内解决。
则考虑回滚莫队,块长为 $\sqrt{n}$ 。我们现在试图一次处理完右端点在某个块 $b$ 中的所有询问。定义该块前最右点为 $R_0$,右端点落在该块中的绳子称为「该块中的绳子」,落在该块前的称为「已处理的绳子」。
显然对于一个从 $x$ 出发的询问,必定先沿着已处理的绳子走到最右端后,再试图沿着该块中的绳子走。所以将该块中的绳子按左端点升序排序后,能走就走即可。
$O(n\log{n})$ 做法
考虑按右端点从左到右地处理每个询问。设当前处理到的右端点为 $R_0$ ,当前从 $x$ 出发的询问的答案为 $a_x$ 。
假设右端点右移一格,加入一条绳子 $[L_0, R_0 + 1]$。对于 $x > L_0$,这条绳子因不在询问区间内而不会产生任何影响。对于 $x \le L_0$,若 $a_x < L_0$ ,则因本来就无法碰到该线段所在位置而不会产生任何影响;而对于 $a_x \ge L_0$,有 $a_x\gets R_0 + 1$。
形式化地,相当于维护序列 $\langle a\rangle$,有两个操作:
- 将区间中不小于 $x$ 的数设为 $y$;
- 单点求值。
这不是 jiry_2 老师的线段树么。
大概就是对每个节点记录最大值与严格次大值 $fir, sec$,和一个二元的 tag $(x, y)$,即将不小于 $x$ 的数改为 $y$。
下传标记操作的时候就将儿子的 $y$ 改成自己的 $y$(由于绳子按右端点升序排序,这样显然更优),而在 $x$ 已有值时应改为较小值。
然后本人因为上传节点操作试图卡常写挂了
于是 $O(n\log n)$ 了。(复杂度证明详见 jls 原课件)
参考代码
1 |
|
参考资料
Segment Tree Beats!