根号分治 莫队 学习笔记

分块真是博大精深呢。。。

  • 一些难以合并的问题可以通过分块去解决。因为它实在是太暴力了。

  • 还有一种思想叫做定期重构。每进行\(\sqrt N\)次操作之后就以\(O(n)\)的代价去重构整个序列。于是在询问的时候,我们最多处理\(\sqrt N\)个操作。

  • 另外,还有一种分类讨论的思想。把某一个值和\(\sqrt N\)进行比较,进而得到两种不同的算法。

P3591 [POI2015]ODW

发现可以分类讨论k。

当k大的时候,一次跨1步(k条边)是可以接受的。

当k小的时候,一次必须多跨几步。于是我们可以预处理出跨\(2^i\)步即\(2^i\times k\)条边的代价,之后可以\(O(logn)\)求得答案。

预处理虽好,但显然是需要\(O(nlogn)\)一次的。

直接跳一个询问的复杂度显然是\(O(len/k)\)

\(k>\sqrt n\)的时候直接跳,否则预处理即可。


P3604 美好的每一天

lxl出的题真妙妙妙妙妙啊。

考虑一个区间可以变成回文一定只有不大于1种字符的出现次数是奇数。

由于只考虑所有26种字符出现次数的奇偶性,我们可以状压后用异或和表示某一段区间。

所以我们可以用前缀和了。某一段区间用\(s_i\oplus s_{j-1}\)即可

再记录某种状态的前缀和有多少种,最后用莫队算法即可实现。

复杂度大概是\(O(n\sqrt n \log n)\)


codechef chef and churu

先考虑一下函数l=r的时候。

直接随便怎么分块,或者用线段树啥的也都可以。
但是由于下面的方法限制,我们最好使用\(O(1)\)处理询问的还可以带修改的分块
记录整块前缀和 以及 块内前缀和。

然后再考虑其它情况:
由于询问的函数也是一段区间,可以考虑对函数进行分块。
记录每一块内有多少个地方的函数包含了\(A[i]\)这个数。
于是,块内修改就可以实现了。

询问的时候,不在整块里面的利用上述方法暴力更新即可。


蒲公英 区间众数

首先对序列进行分块。
然后可以记录前i块每一种数出现次数是多少。

同时记录l-r这一块的众数是什么。这一个在预处理的时候可以直接固定一个i和j就是O(n),然后每次j++只需要扫描第j块中出现的数,因为只有它们可能会成为新众数。

询问时,直接拿出整块的答案。对于两边不到一个整块的答案,由于只有\(O(\sqrt n)\)个数,用上面一样的方法进行计算中间和两边的出现次数即可。最后再全部取一个最大值。

时间和空间复杂度都是\(O(n\sqrt n)\)

同时,本题还有线性空间做法。详见ynoi2019


P3709 大爷的字符串题

啥都不难就读题难。题意是询问某些区间的众数出现次数。
可以考虑用莫队解决。

通常这种求最大值的不是很好维护,我们可以考虑使用回滚莫队实现。

但我们也可以考虑到一个特殊的性质:如果当前的出现次数最多的数是x,出现了t次,那么这个数在减去1的时候,如果已经没有其他数出现了x次,那么说明新的最大出现次数为t-1次(因为刚刚删掉那一个)。

所以直接普通莫队就可以维护。直接做即可。

posted @ 2021-09-23 16:51  lei_yu  阅读(62)  评论(0编辑  收藏  举报