[复习]分块/莫队

首先广为人知的莫队复杂度证明:网上题解证明的大部分有bug,这里改进一下
总询问为q, 总大小为n
莫队复杂度证明:设块长为S,则共有B:=n/S个块
首先考虑块内移动:
单个块考虑
右指针:单调递增,O(n)
左指针:每个询问最多移动块长,设第i块询问个数为f(i)S , f(i)S
总复杂度:
Bn
i=1Bf(i)S = Si=1Bf(i) = Sq
n/Sn+Sq = n2/S+Sq
然后考虑块间移动:
左:2S
右:O(n)
总复杂度 OB(S+n) = O(n2/S+n)
算法总复杂度
O(n+2n2/S+Sq) = O(n2/S+Sq)
对勾函数,当S=n2/m = nm时候,总复杂度为O(nm)
接下来是待修改莫队
设块长为S,共有B:=n/S个块
分开考虑每个指针的移动
时间指针:每个右端点块会最多移动q次,每个左端点块有B个右端点块,所以共有B2个右端点块了,O((ns)2q)
左右指针与刚才的分析一致
所以是O(Sq+n2S+(nS)2q)

根据ouuan dalao的博客, S取值为这个时函数有最小值
然后当qn同阶时候小值,为O(n53)
注意点:
1.求块长时候让S=ceil(n/sqrt(m))
2.求bel数组时候bel[i]=ceil(1.0i/S)
3.分块求L数组与R数组时候 要把最后一个块的R赋值成n
4.注意运算顺序,不要用a[++i]=node(i,a,b)这样的操作,可能先算++i再调用构造函数,也可能先用构造函数再用++i, 所以用逗号表达式一劳永逸++i, a[i] = node(i, a, b)即可
5.注意原始信息和维护信息的区别,比如sort块内的时候不要干扰原始信息

莫队常用技巧:
奇偶性排序:
排序函数里面这么写

if(pos[a.l] != pos[b.l]) pos[a.l]<pos[b.l]
else return pos[a.l]&1?a.r<b.r:a.r>b.r;

大概就是减少右端点移动
回滚莫队:
给出一个长度为n的排列P(P1,P2,...Pn),以及m个询问。每次询问某个区间[l,r]中,最长的值域 连续段长度。
从上到下一次
做法一:权值线段树+普通莫队,但是复杂度过大,是O(lognn(n))
做法二(我的做法):权值并查集,求把连续段整成siz,复杂度O(nlog(n)q+nn)
做法三:题解做法,求出值域上向左向右延伸的最大长度
参考资料:
ouuun的博客

作者:cdsidi

出处:https://www.cnblogs.com/cdsidi/p/15868671.html

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

posted @   CDsidi  阅读(84)  评论(6编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示
more_horiz
keyboard_arrow_up light_mode palette
选择主题