树套树—矩阵修改,单点查询
本文主要介绍一些遇到树套树题目中矩阵修改、单点查询的做法,以及如何将问题转换成简单的模板题。
另外,如果你想看看矩阵修改,矩阵查询,可以看看这个题。
一般,如果这个修改是有逆运算(即可差分的),可以转化为 \(4\) 个差分标记,然后使用树状数组套动态开点线段树 解决。否则就只能使用二维线段树配合永久化标记解决了。
一般树套树的空间复杂度很玄学,最坏能被卡到 \(O(n \log^2 n)\),但随机数据远远够不到。所以建议能写 cdq 还是写 cdq 吧。
[APIO2019] 路灯 - 洛谷P5445
单点修改 \(a_x\),查历史有多少个时刻 \(a_l \sim a_r\) 都是 \(0\)。
首先讲讲一个我想到的错误的做法。对于单点修改相当于对 \(i \sim q\) 时刻的 \(a_x\) 修改,查询相当于问时刻 \(1 \sim i\) 中 \(\sum \limits_{u = l}^r a_u\) 的最小值以及其出现次数。然后发现根本没法做,因为修改是对一列做的,而查询却是和一行有关的,而且维护的信息也比较复杂度,树套树根本不支持维护(似乎 cdq 也不能做)。
正确的做法是将查询看成一个数对 \((l, r)\) ,维护一个答案矩阵,然后看修改会有什么影响。
对于修改,不妨设 \(a_x\) 从 \(0\) 变成 \(1\),找到左边第一个为 \(0\) 的 \(a_y\),以及右边第一个为 \(0\) 的 \(a_z\)。那么对于 \(l \in(y, x], r \in [x, z)\) 的 \((l, r)\),答案从不可行变成了可行。\(a_x\) 从 \(1\) 变 \(0\) 是同理的。
但是如何解决求有多少个时刻是的 \((l, r)\) 都可行呢?假设能使 \((l, r)\) 可行的是若干个区间 \([l_1, r_1), [l_2, r_2), \dots\),那么可以转化为 \(-l_1 + r_1 - l_2 + r_2 + \dots\)
从时刻 \(1\) 枚举到时刻 \(i\) 的过程中,对于那些从不可行变得可行的 \((l, r)\),相当于加入了一个左端点;从可行变得不可行的 \((l, r)\) ,相当于多了一个右端点。那么可以直接转化成一个矩阵加即可。
当然这有一个问题,可能有些 \([l_u, r_u]\) 正好被当前时刻 \(t\) 劈成两半。但这没关系,对于这种情况,\((l, r)\) 对应的值一定是负数,那么直接加上 \(i + 1\) 就是答案了。于是问题就变成了矩阵加,单点查询的问题。
使用树状数组套线段树即可。(二维树状数组开不下。或者可使用 map 之类的神秘手法离散化)
假设是对 \(x \in [xl, xr), y \in [yl, yr)\) 的 \((x, y) + v\)。那么在 \((xl, yl), (xr, yr)\) 打一个 \(+v\) 的标记,\((xr, yl), (xl, yr)\) 打一个 \(-v\) 的标记,然后查询一个前缀矩阵的和即可。
外层树状数组中 \(bit_i\) 相当于记录 \(x \in [x - lowbit(x) + 1, x]\) 这些行的差分数组和,内层线段树就是普通的维护区间和即可。
时间复杂度:\(O(n \log^2 n)\)。
[ZJOI2017] 树状数组 - 洛谷P3688
原题需特判 \(l = 1\) 的情况。
有一个长度为 \(n\) 的
bool数组 \(a\),最初全为 \(0\)。进行 \(T\) 次操作。
- 随机选择 \(x \in [l, r]\),令 \(a_x\) 取反。
- 询问 \(a_u = a_v(u < v)\) 的概率。
首先假设本来 \(a_x\) 为 \(0\) 的概率为 \(q\),\(x\) 没被抽到的概率为 \(q\)。那么执行完取反操作后 \(a_x\) 为 \(0\) 的概率为 \(pq + (1 - p)(1 - q)\)。
在这个题中, \(q = \frac{c - 1}{c}, c = r - l + 1\)。于是我们可以计算出 \(a_u, a_v = 0\) 的概率,然后就做完了。
高高兴兴的写完,然后获得了 \(6pts\) 的战绩。
问题出在哪?因为这种情况有概率出现依次取反操作中,\(a_u, a_v\) 都被取反了,这是不被允许的。(概率为 \(\frac{1}{c^2}\))
所以还是要把他们放在一起讨论。同上面那个题,把 \((u, v)\) 的答案看成一个矩阵,考虑取反操作的影响。同样还是设 \(p\),表示 \(a_u = a_v\) 的概率,不会使 \(a_u, a_v\) 关系发生改变的概率为 \(q\),\(p \leftarrow pq + (1 - p)(1 - q)\)(一次变换)。
对于 \(q\) 分三种情况(对于 \(u, v\) 至少有一个在 \([l, r]\) 的情况,其他的不用管):
- \(q = \frac{c - 1}{c}, u \in [1, l - 1], v \in [l, r]\)
- \(q = \frac{c - 2}{c}, u, v \in [l, r]\)
- \(q = \frac{c - 1}{c}, u \in [l, r], v \in [r + 1, n]\)。
于是就转化为了一个矩阵修改,单点查询的问题
因为这个操作有时是不可逆的(出现分母为 \(0\)),只能考虑硬打标记,使用二维线段树解决。
因为树套树不能 pushdown,所以只能标记永久化,条件是这个标记有交换律(显然交换两次操作没有变化。)
合并标记时,因为这个式子是完全对称的,所以先对 \(p, q\) 做,再对 \(p, t\) 做以及先对 \(q, t\) 做,再对 \(p, t\) 做效果相同,也就可以把比较看成 \(p = 1\) 时经过标记后变成什么。而不用搞个什么 \(p \times x + y\) 的标记。
浙公网安备 33010602011771号