四毛子算法

(日常口胡)

参考资料:luogu日报 LA 模板题解

一个能把 LCA,RMQ 和 LA 问题做到线性的奇怪技巧。
大概就是分块,块的大小为 O(logn),然后整块用原算法,块内可以直接枚举所有可能情况(反正块的大小只有对数级)。

前置知识:ST表做 RMQ,欧拉环游序 LCA 转 RMQ,笛卡尔树,长剖做 LA。

1. LCA#

首先我们按照众所周知的方法把问题转成 RMQ。
然后你发现因为跑的是欧拉序,相邻的两个数的差一定是 11
对于这样一个数列做 RMQ 又叫做 ±1 RMQ 或 约束 RMQ。
然后我们就可以四毛子了!

令块长为 logn2,那么一共就分了 2nlogn 块。
整块直接 ST 表就完事了,时间复杂度 O(2nlognlog(2nlogn))=O(2nlogn(logn+1loglogn))=O(n)
你会发现块长的 log 直接把原来 ST 表预处理的 log 给干掉了。
然后我们再考虑块内。
注意到相邻的两个数的差一定是 11,我们作出差分序列,然后钦定 0 为第一个数还原出一个序列。容易发现这样并没有改变数的大小关系。
因为块长 logn2 实在是太小了,这样操作之后不同的序列一共只有 O(2(logn)/2)=O(n) 种。
于是我们直接暴力枚举,并且对于每一种序列暴力求出区间最大值并且存起来(没必要用 ST 表了)。因此块内时间复杂度为 O(n(logn2)2)=O(n)
O(n)O(1),四毛子算法大成功。

2. RMQ#

我们已经有了快速的 LCA 做法,于是我们考虑将 RMQ 转到 LCA 上来做。
操作是以数组下标和对应的值作为键值建一棵笛卡尔树,容易发现 [l,r] 的 RMQ 就变成了 l,r 在笛卡尔树上的 LCA。
O(n)O(1) 完事。

3. LA#

LA 问题处理起来就比较复杂了。但是和上面处理 LCA 的思路还是相似的。
首先大家知道长链剖分能做到 O(nlogn)O(1),瓶颈在于树上倍增求 2k 级祖先。
我们对原来的算法做一些神奇的优化。我们可以预处理出每一个非叶子结点到子树中任意一个叶子结点的距离(这个预处理显然是线性的),然后我们只需要对所有的叶子结点做倍增就行了。
但我们发现叶子结点的个数最坏还是 O(n) 的。仿照之前的做法,我们考虑将一些叶子结点进行单独处理,只留下 O(nlogn) 个结点,这样预处理就变成线性的了。

方法是这样的:将子树大小不超过 logn4 的结点都删掉,容易发现删去之后树上只有 O(nlogn) 个叶子结点,此时运用上面的操作,时间复杂度是 O(n) 的。
另外已经删去的结点构成了由一些大小不超过 logn4 的森林。那我们只需要枚举所有这样大小的有根树并对每种有根树进行预处理即可。注意到这样树的种类数(实际上就是对应的 Catalan 数)大概是 O(4(logn)/4)=O(n),最终对这些树进行处理的复杂度就是 O(n(logn4)2)=O(n)

可以看出处理手法和 LCA 没什么大的区别,就是实现起来会复杂亿点点。

作者:pjykk

出处:https://www.cnblogs.com/pjykk/p/16534980.html

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   pjykk  阅读(714)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
menu
点击右上角即可分享
微信分享提示