本题是一道单侧递归类线段树问题(这类题比较经典的代表是楼房重建).
观察本题的信息结构,可以想到用线段树维护.下称线段树的节点为区间节点.考虑每个区间节点要存放什么信息.
首先,对于任何一段区间操作序列,都应被处理为一段退格加一段数字的组合.如 B1BB23B45 可以化为 BB245.合并两个子区间时,只需考虑让右子区间的前导 B 与左子区间的一段数字后缀发生消去.如 BB123 和 BB456 合并后的结果应为 BB1456.也有可能右子区间的 B 过多,会把左边的数字全消去,如 BB123 和 BBBB456 合并后的结果是 BBB456.
现在的问题是:对于一个区间节点,右子区间有 \(x\) 个 B,我们怎么迅速获取左子区间删掉 \(x\) 个数位后缀后的信息?再抽象一下这个问题就是:对于任意 \(x\),我们想迅速知道任意区间节点 \(u\) 后接 \(x\) 个 B 的状态,设这个操作为 \(f(u, x)\).
我们不可以让每个区间节点保存完整的数字信息,否则单个节点保存的信息量就达到了 \(\Theta(n)\) 量级,维护的时间复杂度不可承受;如果我们只存下该区间内数字取模后的信息,又不能从之获知这段数字的后缀信息——取模把它破坏了.
考虑单侧递归.维护每个区间节点的数字长度(数位数量)信息,对某个区间节点 \(u\),计算 \(f(u, x)\),同时已知该区间的左儿子区间,右儿子区间分别有 \(p\) 和 \(q\) 个数位.那么:
- 当 \(x = 0\) 时,直接返回 \(u\) 的信息即可.
- 当 \(x \ge p + q\) 时,证明 \(x\) 个
B将把区间的数位删空,同时可能留下更多的B,即返回的是一个纯B的信息,并且B的数量可以平凡计算. - 当 \(p < x < p + q\) 时,这 \(x\) 个
B会把右区间删空,同时影响左区间.我们只需递归左儿子(\(f(l_u, \ldots)\))计算信息.不需递归右儿子是因为右区间数位被删空,信息是平凡的. - 当 \(0 < x \le p\) 时,这 \(x\) 个
B只会影响右区间.故只需递归右儿子(\(f(r_u, \ldots)\)),计算右儿子后接 \(x\) 个B的信息,再与左儿子合并即可……?
这里有一个小问题:左儿子应当同时和右儿子前导的 \(q\) 个 B 抵消,是否需要计算 \(f(l_u, q)\)?
由于每次我们只会在单侧进行递归,因此该计算的递归量级不会超过这个区间节点在线段树上的高度,也即,我们在 \(\Theta(\log n)\) 的时间复杂度下解决了计算任意 \(f(u, x)\) 的问题.
梳理一下目前的进度,首先我们是在考虑区间合并.对节点 \(u\) 的左右节点 \(l_u\),\(r_u\) 合并时,需要用到一个 \(f(l_u, x)\) 的操作.解决 $$
从而我们解决了区间合并的问题.
由此,我们只需在线段树的每个区间节点维护三个信息:
lb:leading backspaces,表示这个区间的前导B数量.v:表示这个区间的数字取模后的结果.cnt:表示这个区间的数字长度.
区间合并解决了,单点更新就被我们解决了.由于我们进行了 \(\Theta(\log n)\) 次区间合并,而单次区间合并的复杂度为 \(\Theta(\log n)\),因此,单次单点更新的复杂度为 \(\Theta(\log^2 n)\).
现在考虑区间查询.我们知道线段树区间查询的本质是将任意区间划分为 \(\Theta(\log n)\) 个区间节点.现在考虑从右向左地考虑这些区间节点,右侧
事实上,对于上面的区间合并操作,我们不必局限于合并两个区间节点,任意的区间合并操作都可以用这个思路进行.
具体而言,我们让区间查询操作支持查询一个区间后接 \(x\) 个 B 的信息状态(即 query 的参数加一个 \(x\),表示要后接 B 的数量).