离线分治算法

常见的离线分治算法通常有

  • 整体二分
  • CDQ 分治
  • 线段树分治
  • 猫树分治
  • 二进制分组

我其实一直很难分清它们的区别,以及并不清楚在什么场景下能够使用,所以我们简单来说一说。

首先是整体二分,这个是最容易分出来的。这样的问题一般答案都有单调性,然后我们用这样的单调性转化为判定问题,并且已经会了单次询问的二分。为了加速整个过程,我们往往判定指针在 \(mid\) 的时候同时回答很多询问。

这里有两种写法,指针的移动次数都是 1 log,但是其中一种可以避免减(撤销),写起来更舒服一点。虽然是离线算法,但是仍然有求值顺序。具体来说,每个询问的 log 次判定是在线的,你必须知道上一次的结果才能知道下一次的询问是啥。在满足这个条件的前提下,可以任意更改顺序。

然后就是这剩下的三个分治算法,其中猫树分治应该是容易被区分的。

猫树分治用于回答一系列静态的关于区间的询问,前提是要能够快速支持两个信息的合并。

剩下的是几个比较麻烦的东西。

CDQ 分治,往往需要修改(元素)对询问的贡献是独立的,这样我们才能够拆开来给它做。然后就相当于把原来动态加入元素的问题变成了静态的。如果你把整个分治过程可持久化下来,发现一次询问其实是拆成了对它前面的 log 个线段树节点的询问,每个节点上维护一个数据结构来支持快速回答询问。

这个东西本身并没有任何顺序的要求,因此如果你必须求出前面的询问才能回答后面的的话,也是可以做的。

是不是应该这么说,这个本质上就是你有元素维,然后你询问的都是前缀相关信息,并且这个信息是可以分批次贡献给答案的。对,也不一定要完全不相关,只要前面信息对后面的影响可以快速计算就可以了。

然后你发现二进制分组就是这个东西的在线版本,没什么好说的。

如果说 CDQ 分治是把询问拆开到修改的组上,那么线段树分治就是把修改拆开到询问的组上。

这样拆有什么好处呢?通常就是把删除变成撤销。

这可能还有一些说法啥的。

你发现,分治算法沿着什么东西分治,是取决于我们的信息具有哪些很好的性质的。常见的维度有时间维、答案维、位置维等等。

这些东西,还是你要抓住询问修改之间的关系,谁对谁有影响,然后把其中一些部分当成整体来做,这样就可以降低时间复杂度了。

感觉还是有些东西没有完全说透。

posted @ 2024-07-12 17:26  PYD1  阅读(8)  评论(0)    收藏  举报