山东二轮省集训 Day2T3 前缀最值 history
题目大意:
给定长度为 \(n\) 的序列 \(a\),再设 \(b_{i} = max_{j = 1}^{i} a_{j}\)。
有 \(q\) 次操作,分一下两种类型:
- \(l,r,x\) 将 \(a_{l} \sim a_{r}\) 都加 \(x\),再更新 \(b_{i} = min(b_{i}, max_{j = 1}^{i} a_{j})\)。
- \(x\) 查询 \(b_{x}\)。
\(n,q \le 5 \times 10^5\)。
强制在线,10s。
解题思路:
这显然得拿一个数据结构维护,还要求在线,那么无非就是:
- 线段树/平衡树。
- 分块。
- 定期回滚,因为这题是将给定的数异或 lstans 的,不是严格的强制在线。
线段树:
其实这题标程是线段树的做法,时间复杂度 \(O(q \times log^2 n)\)。
一个讲题的选手总结了一下说线段树的难点其实本质就是影响子树答案的可能会和前面的有关系。
感觉挺有道理。
分块:
为什么线段树不好做呢?
因为会被前面的最大值影响。
但最大值是唯一的吧?前面不会影响后面太多吧?
分块正好满足这个要求。
那分块要维护什么呢?
首先,他这个题本质是让你维护前缀最大值的历史最小值。
那么维护 当前序列,区间加 tag,块内前缀最大值,答案(算前面块的前缀历史最小值)是不可免的。
能转移了吗?
不能,因为区间加的时候你无法快速的更新答案。
那么为什么?因为区间加的时候,前缀最大值有的加了(块内),有的没加。
而前面的块的最大值在此块中会影响一个前缀。
所以启发我们设 \(pre_{i}\) 表示块的最左边到 \(i\) 受前面的影响所打的 max tag。
而 \(suf_{i}\) 表示 \(i\) 到块尾所收到的块左端到 \(i - 1\) 的最大值。
这样就可以转移了。
但在更新所有 \(pre/suf\) 中,你得从前往后扫块的标号,然后再在块中二分找到第一个不被前面的最大值影响的位置。
所以时间复杂度为 \(O(q \times \frac{n}{B} \log B + q \times B)\)
可以通过调块长,取 \(B = \sqrt{n \log n}\) 来达到 \(O(q \times \sqrt{n \log n})\)。
所以理论上说 \(B = 3000\) 最优。
可惜只是理论上,应该是更新块内的常数比较大,实测块长取大概 \(\frac{\sqrt{n}}{2}\) 时最优。
定期回滚:
你会发现这其实对优化时间复杂度没有任何优化的。
因为这个东西主要优化的是初始化的次数会少一些。
而对于每次修改可以快速知道对以后的贡献是什么。
然而这个题时间复杂度在修改,不能快速查询影响。
所以这条道路我感觉是不可走的,不知道有没有解。
总结:
这个题主要还是显现出了线段树对于分块的另一大劣势。
这个劣势在于会被子树以外的区间干扰。
当然此题线段树做法我会补的。

浙公网安备 33010602011771号