题目大意:
给出一个长为n的序列a,m次查询,对于每次查询给定一个区间[l,r],求出该区间所有子序列中最小值的和。
题目解法:
- 离线算法(莫队)
显然,对于这种没有修改的查询我们可以考虑莫队。难点在于怎么从[l,r]转移到[l,r+1](另外几种转移同理)。我们发现这样的转移对答案带来贡献的即是左端点在[l,r+1]右端点为r+1的所有区间最小值的和。假如我们能将这个值O(1)算出那么复杂度就没有问题了。所以考虑预处理。fr[l][r]表示左端点在[l,r]右端点在r的所有区间最小值的和。
我们想到静态找最小值常用的st算法。经过O(n log n)的预处理后,对于每个区间,我们都可以O(1)求出该区间内的最小值。设[l,r]的最小值在p这个位置,那么显然,当左端点在[l,p]时最小值均为a[p]。我们只需要再计算fr[p+1][r]即可。我们注意到fr数组显然不可能是二维的,那么我们必须要对其进行压缩。我们将第一维去掉得到fr'[r]表示左端点在[1,r],右端点在r的所有区间的最小值和。我们注意到如果将fr'[r]减去左端点在[l,p]右端点在r的所有区间最小值和即可得到fr[p+1][r]。我们进一步注意到因为p位置是该区间内最小值,因此[p+1,r]的数应该均不小于a[p]即 左端点在[l,p]右端点在r的所有区间最小值和 等价于 左端点在[l,p]右端点在p的所有区间最小值和,即fr'[p]。
这样,只要我们将fr'[r]这个数组预处理出来,每次修改O(1)更新即可实现。再引入一个数组lst[i]表示上一个比i小的数(可以用栈、bit等方法求得),那么fr'[r]=fr'[lst[r]]+a[r]*(r-lst[r])。
对称地,我们还需要一个fl数组记录左端点固定的情况,用于处理l变化的转移。
复杂度
- 在线算法
还是从st算法求得的区间最小位置入手。对于一个区间[l,r],若最小的位置为p,那么所有左端点在[l,p]右端点在[p,r]的区间最小值都应该为a[p]。剩下的只有区间全部位于p的一侧的点。
讨论左侧,右侧对称。
左侧的答案即 ,处理一下前缀和即可O(1)算出。
复杂度O(n log n)