洛谷 - P3246 [HNOI2016]序列(莫队+单调栈)

Posted Frozen_Guardian

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了洛谷 - P3246 [HNOI2016]序列(莫队+单调栈)相关的知识,希望对你有一定的参考价值。

题目链接:点击查看

题目大意:给出一个长度为 n n n 的序列,再给出 m m m 次询问,每次询问需要回答一个区间 [ l , r ] [l,r] [l,r] 内所有子区间的最小值之和

题目分析:因为可以离线,所以考虑莫队,这个题的难点是如何处理 [ L , R ] [L,R] [L,R] 递推到 [ L , R + 1 ] [L,R+1] [L,R+1]

[ L , R ] [L,R] [L,R] 推到 [ L , R + 1 ] [L,R+1] [L,R+1],实质上多了 R − L + 2 R-L+2 RL+2 个子区间,分别是 [ L , R + 1 ] , [ L + 1 , R + 1 ] , . . . , [ R + 1 , R + 1 ] [L,R+1],[L+1,R+1],...,[R+1,R+1] [L,R+1],[L+1,R+1],...,[R+1,R+1],我们只需要将这些子区间的最小值之和加上就好了

所以不难想到需要维护一个辅助数组 f [ r ] f[r] f[r],代表前缀 [ 1 : r ] [1:r] [1:r] 的所有后缀 [ 1 : r ] , [ 2 : r ] , . . . , [ r : r ] [1:r],[2:r],...,[r:r] [1:r],[2:r],...,[r:r] 的最小值之和,转移的话可以利用单调栈维护出 l [ r ] l[r] l[r] 代表 r r r 左侧首个小于 a [ r ] a[r] a[r] 的位置,那么有 f [ r ] = f [ l [ r ] ] + ( r − l [ r ] ) ∗ a [ r ] f[r]=f[l[r]]+(r-l[r])*a[r] f[r]=f[l[r]]+(rl[r])a[r],具体意义就是 a [ r ] a[r] a[r] 充当了左端点位于 ( l [ r ] , r ] (l[r],r] (l[r],r] 的这些后缀的最小值

现在我们需要借助 f f f 数组快速求出以 R + 1 R+1 R+1 为右端点,左端点位于区间 [ L , R + 1 ] [L,R+1] [L,R+1] ,右端点为 R + 1 R+1 R+1 的子区间的最小值之和,下文称最小值之和贡献

设区间 [ L , R + 1 ] [L,R+1] [L,R+1] 的最小值的位置为 p p p,不难看出左端点位于 [ L , p ] [L,p] [L,p] 的子区间的贡献为 a [ p ] a[p] a[p],现在我们的问题变成如何计算左端点位于 ( p , R + 1 ] (p,R+1] (p,R+1] 的子区间的贡献

用我们刚才的 f f f 公式展开看看?

x = R + 1 x=R+1 x=R+1 f [ x ] = f [ l [ x ] ] + ( x − l [ x ] ) ∗ a [ x ] f[x]=f[l[x]]+(x-l[x])*a[x] f[x]=f[l[x]]+(xl[x])a[x]

p r e = l [ x ] pre=l[x] pre=l[x] f [ p r e ] = f [ l [ p r e ] ] + ( p r e − l [ p r e ] ) ∗ a [ p r e ] f[pre]=f[l[pre]]+(pre-l[pre])*a[pre] f[pre]=f[l[pre]]+(prel[pre])a[pre]

p p r e = l [ p r e ] ppre=l[pre] ppre=l[pre] f [ p p r e ] = f [ l [ p p r e ] ] + ( p p r e − l [ p p r e ] ) ∗ a [ p p r e ] f[ppre]=f[l[ppre]]+(ppre-l[ppre])*a[ppre] f[ppre]=f[l[ppre]]+(pprel[ppre])a[ppre]

不难发现我们会沿着一个 a [ p r e ] a[pre] a[pre] 递减的序列一直迭代,即 a [ p p r e ] < a [ p r e ] < a [ x ] a[ppre]<a[pre]<a[x] a[ppre]<a[pre]<a[x],并且直到 p p p 停止,因为 a [ p ] a[p] a[p] 是区间 [ L , R + 1 ] [L,R+1] [L,R+1] 中的最小值呀, a [ p ] a[p] a[p] 前面不会再有比它小的数字了

如果将上面的公式自底向上套进去的话,我们会惊奇的发现, f [ R + 1 ] − f [ p ] f[R+1]-f[p] f[R+1]f[p] 即为所求,也就是左端点位于 ( p , R + 1 ] (p,R+1] (p,R+1] ,右端点为 R + 1 R+1 R+1 的这些子区间的贡献

到此为止我们可以利用 R M Q RMQ RMQ 预处理区间最小值的位置然后 O ( 1 ) O(1) O(1) 进行区间 [ L , R ] [L,R] [L,R] [ L , R + 1 ] [L,R+1] [L,R+1] 的扩展了,对于剩下的 [ L , R − 1 ] , [ L + 1 , R ] , [ L − 1 , R ] [L,R-1],[L+1,R],[L-1,R] [L,R1],[L+1,R],[L1,R] ,分析起来同理,这里不做过多赘述

有一个小问题就是,这个题的莫队的修改顺序需要先加后减,不然会又WA又RE的

那么莫队的时间复杂度就是 O ( n l o g n + n n ) = O ( n n ) O(nlogn+n\\sqrt{n})=O(n\\sqrt{n}) O(nlogn+nn )=O(nn )


打一个分割线,下面讲讲另一种写法

注意到这个题很巧妙地预处理出了 f f f 数组辅助莫队的转移,所以我们既然想到了 f f f 数组,为什么不思考一下能否直接用 f f f 数组计算区间的贡献呢?

给定区间 [ L , R ] [L,R] [L,R],还是设 p p p 为区间最小值的位置,我们将总贡献分成三份:区间 [ L , R ] [L,R] [L,R] 的贡献 = 区间 [ L , p ) [L,p) [L,p) 的贡献 + 区间 ( p ,

以上是关于洛谷 - P3246 [HNOI2016]序列(莫队+单调栈)的主要内容,如果未能解决你的问题,请参考以下文章

P3246 [HNOI2016]序列(查询l-r中所有区间的最小值之和)

「HNOI2016」序列

洛谷P3245 [HNOI2016]大数 莫队

bzoj4540: [Hnoi2016]序列

4542: [Hnoi2016]大数|莫队

[bzoj4540][Hnoi2016]序列——单调栈+莫队+RMQ