题意
给定长度为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]的增量也是相同的,只需求个倒序的单调栈即可。