Solution P11982 | while seeing orderly streetlights

· · 题解

思路借鉴了 @Daniel_lele,这里给出一些具体实现细节。

考虑根号重构,每次把接下来 \sqrt{n} 次要修改的位置拿出来,令其下标序列为 [p_1,p_2,\cdots,p_k]

Part 1

先计算至少有一个路灯在 p 中的二元组。构建一个新的序列如下:

[p_1,f(p_1,p_2),p_2,f(p_2,p_3),\cdots,f(p_{k-1},p_k),p_k]

其中 f(p_i,p_{i+1}) 表示在 p_ip_{i+1}(均不含)之间的最高的路灯。所有 f 在这个块内均不会被修改,但是 p_i 的高度会被修改。

Part 2

然后考虑两个路灯都不在 p 中的贡献。先直接在原序列中去掉被修改过的路灯,剩下的可以 \mathcal{O}(n) 单调栈跑出所有合法二元组,给它们编号,并用编号建立出它们的树形关系。

修改一个 p_i 的高度时会破坏一些原有的二元组。找到跨过 p_i 的两端点距离最近的二元组编号 low_i,那么从它开始往上的一条链会被标记为不再合法。

这可以用树剖+线段树维护。具体地,给树上所有点一个标记值 w_i,每次把一条链上的 w_i\pm 1(加入或撤销),并查询全局 0 的个数(即没有被标记过的点树),这通过维护区间最小值及其个数就能做到。

还有一个问题是怎么找 low_i。这里提供一个算法:维护一个序列 d,对于每个二元组 [l,r],让 d_l1,让 d_{r-1}1。求 low_i 的时候相当于找到一个最小的 x 使 \sum \limits_{k=x}^{p_i-1} d_k >0。于是把 d 求个前缀和后跑单调栈就可以线性预处理 low_i

现在来看看复杂度。重构的时候,线段树、树剖、单调栈,这些预处理全都是线性的;每次查询会把 \sqrt{n} 个点拿出来再跑单调栈;一些 \text{polylog} 的东西忽略不计(实际上运行起来不能忽略不计),复杂度 \mathcal{O}(n\sqrt{n})

目前只在 loj 过了 /kel

听耳边熙熙攘攘的声音如风

辨别不出你方位是我的瞳孔

当看见一排工整有序的路灯

低着头苏醒了