题意
给定长度为
n
的序列:
解法
Philips Weng大神(%%%)用一个线段树存8个值的
nlog2n
做法过了,但我这里介绍一个
nn−−√
的莫队算法(T3也是莫队,D1T1也是分块,这是有多喜欢
n−−√
?)。
我们假设当前求出了区间
[l,r]
的答案,现在要求
[l,r+1]
相对于
[l,r]
增加的答案(
[l,r−1]
的答案可以用原答案减去
[l,r]
相对于
[l,r−1]
增加的答案)。
新增的答案为
∑r+1i=lmin(i,r+1)
,
min(i,r+1)
表示区间
[i,r+1]
中的最小值。有一个暴力的想法,维护一个从左至右单调递增的栈,然后扫一遍栈,算出贡献。但是每次构一次栈显然是不能接受的。
于是我们可以预处理出一个从
1
开始的栈,当做到一个位置
回到刚刚的问题,我们可以找到
[l,r+1]
中最小值的位置
pos
,对于
i∈[l,pos]
,它们对增量的贡献为
a[pos]
;而对于
i∈[pos+1,r+1]
,我们相当于要跟原来一样构一个单调栈算一下贡献,但是我们发现,这个单调栈是我们预处理出的 到
r+1
的前缀单调栈的, 开头为
pos
的“后缀”。这个是显然的,因为
a[pos]
是该区间的最小值,所以
pos
一定会出现在到
r+1
的前缀单调栈中。所以这部分的贡献
=sum[r+1]−sum[pos]
。总贡献为
(pos−l+1)∗a[pos]+sum[r+1]−sum[pos]
。我们只要知道区间最小值的位置就能
O(1)
求出答案增量了,而这个就是经典的
RMQ
了。
对于求
[l−1,r]
的增量也是相同的,只需求个倒序的单调栈即可。