【学习笔记】根号算法
1.分块
最基础的就是区间修改查询。
我们把整个序列割成
考虑对于整块我们类似线段树的维护方法打 tag,然后对于散块 直接暴力。
分析复杂度,最多有
由基本不等式可得
所以当
这就是基本分块了,但是对于一些 毒瘤 题可能要玄学修改块长。
很多时候分块用于处理线段树不好处理的问题(比如交换两个数的位置)或者用来平衡复杂度(线段树树状数组固定都是
2.莫队
- 普通莫队
对于一些区间询问,我们可以考虑维护端点,然后一个一个移到规定的询问区间,在这中间进行
很显然如果按照输入顺序搞会卡到
我们考虑把询问离线下来,然后 按操作左右端点分块。具体地,如果左端点 所在的块 不同就按左端点排,如果左端点相同就按右端点排。
然后重新根据上面的思路进行操作,就结束了。
考虑复杂度为什么是对的。
首先修改操作是
然后转到另一个块,用不超过
所以总共是
那么我们要让
好像有人说莫队正确块长应该取
一个比较显然的优化是将右端点进行奇偶性排序,也就是如果是块的编号奇偶不同就从大到小/从小到大。这样子我们可以在路上顺便一起处理了。
看不懂就记板子。
inline bool operator <(const QQr &stmp)const{ if(b[ql]!=b[stmp.ql])return b[ql]<b[stmp.ql]; return (b[ql]&1?qr<stmp.qr:qr>stmp.qr); }
- 带修莫队
考虑再开一个时间维度。询问时把时间一起调。块长要设成
有一个很好玩的 trick 是修改值直接把待改的和当前的值交换就好,因为如果要往回退时间维度肯定会调回来然后这两个值就会被换回来。
- 回滚莫队
对于一些增加删除只能支持一种的莫队,我们可以考虑回滚。
显然这道题很难进行删除操作。这一次我们对于每个块单独进行处理。
先把左右端点在同一块的询问暴力掉。复杂度
然后假设我们的左端点固定,只看右端点,我们会发现右端点一直在往右走,所以右端点对于每一个块仍然是
但是我们没有考虑的左端点呢?
我们对于每一个询问都单独进行左端点的添加。即,记录不管左端点(左端点在这个块的最右端的右端)时当前答案,然后左端点开始加点,得到答案,把左端点对一些数组的改动回滚回来,把答案重新回滚回左端点移动前的答案。因为左端点每次最多移动
- 树上莫队
如果是 dfs 序,就直接普通莫队做了。
- 欧拉序
dfs 序在退出的时候不会记录,但是欧拉序会记录,也就是说每个节点在序列中出现两次,扫到的时候出现一次
推荐自己画一棵树然后求欧拉序捏。
我们很容易知道在欧拉序上一段区间出现过两次的点并不在我们的询问路径上。
对于在欧拉序上的点
否则是
然后如果是第二种情况要添加上
- 二次离线莫队
在一些莫队问题中若更新答案的复杂度
同时一般情况下
我们现在考虑端点移动造成的贡献。
当
当
同样地推一下发现另外两种情况只不过是换了符号。
其中
然后我们看剩下的那两个。
那么一次的转移就是
也就是这些段是连续的。我们可以搞一个五元组
按照
莫队花费的总复杂度是
有一个常数优化能够优化成
因为是毒瘤且冷门的根号算法,还跟某人有关,buff 叠满,所以必要的常数优化是很重要的。
诸如 逆序对 之类的问题会带有方向性,需要我们从前往后从后往前扫两遍。
然后对于这个有很多的不同,所以建议每次做莫队二离的题都重新手推一遍再写。
3.根号分治
原理是一种暴力,根据询问范围使用不同的做法。询问范围由一个阈值
我们考虑维护一个答案数组
同时我们仍然维护原数组
对于操作一,若我们用
对于操作二,若
这种复杂度见过很多次了,
根号分治很多时候看不出来,但 某个值总量一定 时可以尝试考虑根号分治。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具