LG5608 [Ynoi2013] 文化课

发布于 2021-08-13  961 次阅读


题目链接

题目大意

现在有一个数字序列 ${a_1,~a_2,\dots,~a_n}$ 和一个运算符序列 ${p_1,~p_2,\dots,~a_{n-1}}$。

定义 $w(l,~r)$ 表示 $a_l~p_l~a_{l+1}~p_{l+1}~\dots~a_{r-1}~p_{r-1}~a_r$ 对 $10^9+7$ 取模后的结果。

现有 $m$ 个操作:

  1. 将 $a_l \sim a_r$ 修改为 $x$。
  2. 将 $p_l \sim p_r$ 修改为 $x$。
  3. 求 $w(l,~r)$ 的值。

$1 \le n,~m \le 10^5,~1 \le a_i < 2^{32},~p_i \in {+,~\times}$

分析

考虑我们如何暴力计算 $w(l,~r)$,我们会先将 $[l,~r]$ 区间切分为若干满足每段内所有符号均为 $\times$ 的极长段。如 $1+3\times5\times7+9\times11$ 将被分割为 $[1],~[3,~5,~7],~[9,~11]$。分割完后我们对每个极长段求出段内乘积,再将所有段的结果加起来即为我们所求的 $w(l,~r)$。

先考虑没有修改操作只有查询操作的情况,对于每一个查询区间我们需要知道区间内所有极长段的乘积之和,容易想到使用线段树维护。线段树上每一个结点维护对应区间的最左端极长段乘积,最右端极长段乘积和其他极长段乘积之和。合并两个区间信息时判断左结点的最右端极长段与右结点的最左端极长段是否能够连接即可。

考虑加入 1 操作,对 $a$ 序列的区间修改操作在线段树上体现为对 $O(\log n)$ 个区间的整段修改操作。我们发现对于一个线段树结点,当他对应的区间被整段修改后其所有极长段左右端点均没有发生变化,而所有极长段的段内乘积会发生改变。我们考虑对于每个节点维护一个桶维护其所有非最左端也非最右端的极长段长度,在将该节点整段修改为 $x$ 时只需要将答案更新为 $\sum_{i} x^{i} \times midLen[i]$ 即可。同时我们也需要记录最左端极长段长度和最右端极长段长度,这样在合并线段树结点信息时即可将左结点的最右端极长段与右结点的最左端极长段合并后构成的新极长段长度加入桶中。

考虑加入 2 操作,同样我们也可以将对 $p$ 序列的区间修改在线段树上体现为对 $O(\log n)$ 个区间的整段修改操作。由于修改为 $+$ 和修改为 $\times$ 的情况不同,我们分开讨论:

  1. 整段修改为 $+$: 修改后该区间内会产生 $len$ 个长为 $1$ 的极长段,$ans$ 将变为 $\sum_{i=l+1}^{r-1} a_i$。为此对每个节点我们维护整段元素和以快速维护此修改操作。
  2. 整段修改为 $\times$: 修改后该区间内会产生 $1$ 个长为 $len$ 的极长段,此时该极长段的乘积为 $\prod_{i=l}^{r} a_i$。为此对每个节点我们维护整段元素乘积以快速维护此修改操作。

在线段树上维护上述所有信息即可,此时时间复杂度为 $O(n \times \log n + m \times n \times \log n)$,空间复杂度为 $O(n \times \log n)$。时间复杂度与空间复杂度均无法通过此题。

优化 1

对于每个线段树结点,其区间内所有极长段的长度之和为 $len$,因此最多只会存在 $\sqrt {len}$ 种不同的极长段长度,将相同长度的极长段的信息在一起存储,使用大小为 $\sqrt {len}$ 的 vector 存储即可。

此时时间复杂度 $O(n + m \times \sqrt n \times \log n)$,空间复杂度 $O(n)$。时间复杂度仍无法通过此题。

优化 2

在区间修改元素值时我们对 $O(\sqrt n)$ 个长度都 $O(\log n)$ 求该长度对应区间修改后的乘积。考虑存储连续段长度时按连续段长度升序存储,需要对第 $i$ 个长度求值时从第 $i-1$ 个长度对应的答案转移过来。因为 $O(\sum_{i} \log (a_i - a_{i-1})) = O(\log a_n) = O(\sqrt len)$,所以花在对 $O(\sqrt n)$ 个长度求值的时间复杂度转为 $O(\sqrt n)$。

此时时间复杂度 $O(n + m \times \sqrt n)$,空间复杂度 $O(n)$,可以通过此题。

也可以考虑以恰当块长对线段树底层进行分块以继续减少空间占用。

代码

View on GitHub


我缓慢吐出一串啊吧啊吧并不再想说话