CF837G Functions On The Segments
- 有 \(n\) 个分段函数,第 \(i\) 个函数形如:
\[f_i(x)=\begin{cases}y1_i,\space \space \space \space \space \space \space \space\space \space \space \space x\le x1_i\\a_ix+b_i,\space \space \space \space x1_i<x\le x2_i\\ y2_i,\space \space \space \space \space \space \space \space\space \space \space \space x>x2_i\end{cases} \]
有 \(m\) 次询问,每次询问给出 \(l,r,x\),求 \(\sum\limits_{i=l}^r f_i(x)\)。
\(n\le 7.5\times 10^4\),\(m\le 5\times 10^5\)。强制在线。
首先,所有函数都可以表达成一次分段函数的形式(注意这里强调的是形式上相同)。
即 \(f_i(x)=p_ix+q_i\),其中:
-
当 \(x\le x1_i\) 时,\(p_i=0,q_i=y1_i\)。
-
当 \(x1_i<x\le x2_i\) 时,\(p_i=a_i,q_i=b_i\)。
-
当 \(x>x2_i\) 时,\(p_i=0,q_i=y2_i\)。
考虑对于一次查询,求的就是:
\(x\) 给定,只需要维护 \(p_i\) 以及 \(q_i\) 的区间和即可。
最大的麻烦是 \(p_i\) 和 \(q_i\) 在动态变化。不过我们考虑将所有分段函数分段的起点全部存到一个数组 \(P\) 里面。并将其从小到大排序,设其大小为 \(k\)。
则对于同一条分段函数 \(f_i(x)\) 来说,当自变量 \(x\) 取值为 \(x_1,x_2\),满足存在一个 \(j\,(1\le j< k)\) 使得 \(x_1,x_2\in[P_j,P_{j+1})\) 时,\(\boldsymbol{f_i(x_1)=f_i(x_2)}\)。
就是说将这些点投影到数轴上时,这些点将数轴分成若干段,若自变量 \(x\) 取在相同的一段里时,则函数值相同。
很好理解,因为同一段内不存在一个分段函数的起点,对于任意函数来说不存在一个函数发生变化的地方。
因此我们对于数轴上的每一段,维护这一段对应的 \(p_i,q_i\) 的区间和。由于强制在线,考虑使用可持久化线段树维护每一段的信息。
将所有变化表示成差分的形式并离线扫描线。当开启一个新段的时候,在上一段版本的基础上扫描并进行这一段的修改。由于每一段可能产生多次修改,因此主席树上的版本仍然记“第几次修改之后”,再维护一个新数组记录每一段的最终版本(即最后一次修改的版本)。
查询时,先二分找到 \(x\) 在哪一段,然后在对应的版本上查询即可。
时间复杂度为 \(\mathcal{O}((n+m)\log n)\),空间复杂度为 \(\mathcal{O}(n\log n)\)。

浙公网安备 33010602011771号