题目链接
原问题没法直接维护。先推式子,看看能得到什么。
设 f(l,r) 表示给定 l,r 时的答案。那么根据定义,有:
f(l,r)=r∑len=ln−len+1∑i=1i+len−1∑j=iaj
记 s(m)=∑mi=1ai,则我们可以去掉第三个求和符号:
f(l,r)=r∑len=ln−len+1∑i=1[s(i+len−1)−s(i−1)]
记 ss(m)=∑mi=1s(i),继续推导,去掉第二个求和符号:
f(l,r)=r∑len=l[ss(n)−ss(len−1)+ss(n−len)]
记 sss(m)=∑mi=1ss(i),继续推导,去掉最后的求和符号:
(为了应对边界条件,定义当 m≤0 时,ss(m)=sss(m)=0,这是自然的。)
f(l,r)=(r−l+1)ss(n)+sss(r−1)−sss(l−2)+sss(n−l)−sss(n−r−1)
以上,我们就去掉了所有的求和符号,这是进一步优化算法的基础。实际上,有了这个式子之后,我们就可以做到 O(1) 查询。但修改时,我们必须重新求出 s,ss,sss 数组,这样做的时间复杂度为 O(n)。
想想怎么优化。看到题目中的区间操作,很自然地想到用线段树维护。那么,维护什么以及如何维护呢?
首先明确我们的需求:区间修改,快速计算 ss(m),sss(m)。从这里以后有两条路:
-
预处理出原序列 a 的 ss 数组。修改时,考察 a 的区间加对 ss 产生的影响,用线段树维护 ss 的区间和。维护 ss 的好处在于:sss 是 ss 的前缀和,因此要求 sss 时,只要在线段树上查询 ss 的区间和即可。
-
维护 a 和一些辅助数组,把 ss 和 sss 都写成用 a 表示的形式。
注意 ss 和 sss 是不能作为区间信息维护的。实际上,带“前缀”的信息都不能作为区间信息维护。以更简单的一阶前缀和 s 为例,考虑这样的问题:区间加,求任意位置的前缀和。在线段树中,对于一个区间 [l,r],我们不能维护区间 [l,r] 的前缀和 s,因为这不能合并:[l,mid] 的前缀和与 [mid+1,r] 的前缀和相加,不能得到 [l,r] 的前缀和。我们只能维护 [l,r] 的区间和,而这个信息是可以合并的。求某个位置 p 的前缀和,看作 [1,p] 的区间和即可。
如果选择这种方式,要继续推式子。
下面选用第二种方法。继续推导:
ss(m)=m∑i=1s(i)=m∑i=1i∑j=1aj=m∑i=1(m−i+1)ai=(m+1)s(m)−m∑i=1iai
这里出现了新的求和式:∑mi=1iai,我们记为 si(m),则
ss(m)=(m+1)s(m)−si(m)
这样我们就把 ss 用 s 和 si 表示了出来。显然,s(m) 是容易用 a 表示的:对 a 求区间和即可。而 si 也是可以维护的——它不是某种“前缀”和的形式,因此可以在线段树上合并信息。至于如何维护,等会再说。
下面推导 sss 的式子:
sss(m)=m∑i=1ss(i)=m∑i=1[(i+1)s(i)−si(i)]=ss(m)+m∑i=1is(i)−m∑i=1si(i)
∑mi=1is(i) 和 ∑mi=1si(i) 都不能直接维护,继续推导:
m∑i=1is(i)=m∑i=1(ii∑j=1aj)=m∑i=1(aim∑j=ij)=m∑i=112(m+i)(m−i+1)ai=12m∑i=1(m2−m+i2+i)ai=12m(m−1)s(m)+12si(m)+12m∑i=1i2ai
(推到第二个等号的要点在于计算每个 ai 前的系数:这里,每个 ai 从 i 开始计算,系数为 i,然后为 i+1,i+2,一直到 m,因此总系数为 ∑mj=ij。)
记 sii(m)=∑mi=1i2ai,和 si 类似,这也是可以合并的信息,因此可以用线段树维护。那么
m∑i=1is(i)=12m(m−1)s(m)+12si(m)+12sii(m)
接着来推导 sss 的式子中剩下的另一个和式:∑mi=1si(i):
m∑i=1si(i)=m∑i=1i∑j=1jaj=m∑i=1(m−i+1)iai=(m+1)si(m)−sii(m)
(这里推导的要点在于把 iai 看作一个整体,然后推导方式和 ss 相同,只是把求和对象从 ai 换成了 iai。)
至此,我们终于可以写出 sss 的式子:
sss(m)=12m(m+1)s(m)+ss(m)−(m+12)si(m)+12sii(m)
从 ss 和 sss 的式子可以看出,我们需要维护的量有 s,si 和 sii。最后要考虑的是怎么维护区间加对这些量的影响。
考虑一个区间 [l,r],设它的三个量为 s,si 和 sii(定义同上文)。设区间加 d 后,新的量为 s′,si′ 和 sii′。那么
s′=r∑i=l(ai+d)=s+dr∑i=l1si′=r∑i=li(ai+d)=si+dr∑i=lisii′=r∑i=li2(ai+d)=sii+dr∑i=li2
对于 ∑ri=l1,∑ri=li 和 ∑ri=li2,可以用公式求,也可以预处理后查表。这显然是好维护的。
回顾一下我们要做什么:
- 在线段树上维护 s,si 和 sii。
- 对于每次询问,根据公式求出答案。公式中要用到 ss 和 sss,这些也要代入公式求,但总归能化到我们维护的三个量。
每次询问时,我们只会在线段树上查询常数次,所以总时间复杂度为 O(n+mlogn)。
综上所述,我们就解决了这个问题。
AC 记录
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】