扫描线优化 LIS
感觉是一种没啥用的 trick,但由于自己手搓出来了,就发出来写一下。
我们知道,LIS 有一种非常朴素的 DP 做法:令 \(f_i\) 表示只考虑前 \(i\) 个数且强制选 \(a_i\) 的 LIS,则 \(f_i=\max\limits_{j \in [0,i)}^{a_j<a_i}f_j+1\)。这个东西直接做的话复杂度是 \(O\left(n^2\right)\)。
于是你想着怎么优化这个东西。你先构造一个平面直角坐标系,在这个坐标系上放 \(n\) 个点,第 \(i\) 个点 \(P_i=(i,a_i)\)。于是你注意到这么一个事实:对于 \(i\),其合法的转移点必然位于 \(P_i\) 的左下角。
于是你就好办了。你类似扫描线,把所有点按 \(a_i\) 从小到大排序,同时你有一个空的集合 \(S\),现在你要把点按照排序好的顺序依次加入 \(S\)。加入 \(P_i\) 的时候,\(f_i=\max\limits_{P_j \in S,j < i}f_j+1\)。这个你随便用一个支持插入和查询前缀最大值的数据结构维护一下就好了。如果你写的是最长上升子序列的话对于 \(a_i\) 相同的点得全部更新完答案后再一起插入到数据结构中。如果你是最长不降子序列的话得把所有 \(a_i\) 相同的点按照 \(i\) 再从小到大排序,排序完之后每个点更新完答案后就立刻插入到数据结构中。
时间复杂度取决于你所用的数据结构。你像我用线段树的话就是 \(O\left(n \log n\right)\)。

浙公网安备 33010602011771号