【HNOI2016】序列

题意

给定长度为 n 的序列:a1,a2,...,an q 个询问,每个询问给一个区间,询问该区间的不同子序列的最小值之和。
n,q105

解法

     Philips Weng大神(%%%)用一个线段树存8个值的 nlog2n 做法过了,但我这里介绍一个 nn 的莫队算法(T3也是莫队,D1T1也是分块,这是有多喜欢 n ?)。
     我们假设当前求出了区间 [l,r] 的答案,现在要求 [l,r+1] 相对于 [l,r] 增加的答案( [l,r1] 的答案可以用原答案减去 [l,r] 相对于 [l,r1] 增加的答案)。
     新增的答案为 r+1i=lmin(i,r+1) min(i,r+1) 表示区间 [i,r+1] 中的最小值。有一个暴力的想法,维护一个从左至右单调递增的栈,然后扫一遍栈,算出贡献。但是每次构一次栈显然是不能接受的。
     于是我们可以预处理出一个从 1 开始的栈,当做到一个位置i时,栈中它底下一个的位置为序列中它左边第一个小于它的位置。此时的栈为 1 i的一个单调递增序列,此时的贡献也很好统计,我们记为 sum[i] (因为总贡献为相邻元素的贡献之和,所以它相当于栈中元素的贡献前缀和)。
     回到刚刚的问题,我们可以找到 [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] 。总贡献为 (posl+1)a[pos]+sum[r+1]sum[pos] 。我们只要知道区间最小值的位置就能 O(1) 求出答案增量了,而这个就是经典的 RMQ 了。
     对于求 [l1,r] 的增量也是相同的,只需求个倒序的单调栈即可。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值