四毛子算法口胡
一个能把 LCA,RMQ 和 LA 问题做到线性的奇怪技巧。
大概就是分块,块的大小为 \(O(\log n)\),然后整块用原算法,块内可以直接枚举所有可能情况(反正块的大小只有对数级)。
在某场初赛之后这个技巧应该说是普及了。
1. LCA
首先我们按照众所周知的方法把问题转成 RMQ。
2026 upd:这年代 dfs 序是主流,但是这里采用古法欧拉序,性质更好。
然后你发现因为跑的是欧拉序,相邻的两个数的差一定是 \(1\) 或 \(-1\)。
对于这样一个数列做 RMQ 又叫做 \(\pm1\) RMQ 或 约束 RMQ。
然后就是四毛子操作,令块长为 \(\dfrac{\log n}{2}\),那么一共就分了 \(\dfrac{2n}{\log n}\) 块。
整块 ST 表时间复杂度
块长的 \(\log\) 把 ST 表的 \(\log\) 给干掉了。
然后考虑块内。注意到相邻的两个数的差一定是 \(1\) 或 \(-1\),进行离散化风味操作,作出差分序列,钦定 \(0\) 为第一个数还原出一个标准的序列。
块长 \(\dfrac{\log n}{2}\) 实在是太小了,这样操作之后不同的序列一共只有 \(O(2^{(\log n)/2})=O(\sqrt{n})\) 种,可以看出块长那个二分之一系数的细节。
然后直接暴力枚举,并且对于每一种序列暴力求出区间最大值并且存起来(没必要用 ST 表了)。因此块内时间复杂度为 \(O\left(\sqrt{n}\left(\dfrac{\log n}{2}\right)^2\right)=O(n)\)。
于是就 \(O(n)-O(1)\) 了。
2. RMQ
已经有了快速的 LCA 做法,考虑将 RMQ 转到 LCA 上来做。
建笛卡尔树,容易发现 \([l,r]\) 的 RMQ 就变成了 \(l,r\) 在笛卡尔树上的 LCA。
\(O(n)-O(1)\)。
3. LA
LA 问题处理起来就比较复杂了,大概原理是树上的分块类似物,不是很懂。
首先长链剖分 \(O(n\log n)-O(1)\) 的瓶颈在于预处理的树上倍增。
做一些神奇的优化,预处理出每一个非叶子结点到子树中任意一个叶子结点的距离(这个预处理显然是线性的),于是只需要对所有的叶子结点做倍增就行了。
但我们发现叶子结点的个数最坏还是 \(O(n)\) 的。仿照之前的做法,我们考虑将一些叶子结点进行单独处理,只留下 \(O\left(\dfrac{n}{\log n}\right)\) 个结点,这样预处理就变成线性的了。
方法是这样的:将子树大小不超过 \(\dfrac{\log n}{4}\) 的结点都删掉,容易发现删去之后树上只有 \(O\left(\dfrac{n}{\log n}\right)\) 个叶子结点,此时运用上面的操作,时间复杂度是 \(O(n)\) 的。
另外已经删去的结点构成了由一些大小不超过 \(\dfrac{\log n}{4}\) 的森林。那我们只需要枚举所有这样大小的有根树并对每种有根树进行预处理即可。注意到这样树的种类数(实际上就是对应的 Catalan 数)大概是 \(O(4^{(\log n)/4})=O(\sqrt{n})\),最终对这些树进行处理的复杂度就是 \(O\left(\sqrt{n}\left(\dfrac{\log n}{4}\right)^2\right)=O(n)\)。

浙公网安备 33010602011771号