线段树分治
前言
古人有云,一切恐惧的来源都是火力不足。
所以发展才是硬道理,我又开始补新算法了。
引入
做久了数据结构会发现都有一个共性,即通常会有修改与查询操作(这里说的不太绝对是因为我见识短浅不敢说绝对了)。
那么对于修改操作,通常分为对数据的修改(比如大部分经典板子)和对其它信息的修改(比如维护图上的加边)。这里不提前者,只说后者。
比如我们有三个操作,加入一条边,删除一条边,查询两点是否连通。加入和查询很简单,并查集维护一下即可。但是删除操作很困难,当然我们可以用 LCT 维护,但是我不会。这时候就要考虑线段树分治了。
介绍
线段树分治通常用于维护被维护信息存在加入和删除操作的问题。
为了方便叙述,我们就 P5787 二分图 /【模板】线段树分治 来说,但是语言还是会很泛化。
既然你的每条边有加入删除两种操作,那么在时间轴上,它存在的时间就是一个区间。
我们可以立刻想到一个暴力,维护每个时间点上有哪些信息存在,就是对每个时间点开个 vector
存有哪些边,然后对每个时间点求解。
但是直接暴力这样显然时间空间都会爆掉,那么可以考虑像线段树一样,把每个区间分为 $\log n$ 个区间,对线段树上的每个结点维护一个 vector
,然后利用类似标记永久化的思路遍历线段树,由于退出结点时需要删除,可以用可撤销并查集维护。这样遍历线段树的时间复杂度为 $O(n+m\log n)$(因为每个区间会被分为 $\log n$ 个区间),然后可撤销并查集的复杂度为 $O(\log m)$(因为每条边只会同时存在一个),总复杂度 $O(m\log n\log m)$,空间复杂度 $O(n+m)$。
例题
P5787 二分图 /【模板】线段树分治
假如你理解了线段树分治你就会发现这道题有多简单,而且因为刚刚也讲过了,在此略过。
P7470 [NOI Online 2021 提高组] 岛屿探险
这道题虽然每个岛不会出现和消失,但是我们分析一下:
对于 $d<b$ 很简单,要计算的就是 $a\oplus c\le d$,把 $a$ 插入 01Trie 后用二元组 $(c,d)$ 去查询。
对于 $d\ge b$ 要计算的就是 $c\oplus a\le b$,发现和上面是对称的,可以把 $c$ 全部插入 01Trie 后用二元组 $(a,b)$ 去给 Trie 打标记,然后再用 $c$ 去统计。
容易发现在对称情况下,每个 $c$ 是会被添加和消除的。由于计数具有可减性,我们可以直接拆成 $[1,l-1],[1,r]$ 两个区间后用 CDQ 分治做(就是一个二维偏序)。但是我们也可以线段树分治后在每个结点上转化为一维偏序。两种方法复杂度均为 $O(n\log n\log V)$(但是有一说一这道题 cdq 要好写一点)。