[BZOJ4540][HNOI2016]序列 莫队
4540: [Hnoi2016]序列
Time Limit: 20 Sec Memory Limit: 512 MB
Description
给定长度为n的序列:a1,a2,…,an,记为a[1:n]。类似地,a[l:r](1≤l≤r≤N)是指序列:al,al+1,…,ar-
1,ar。若1≤l≤s≤t≤r≤n,则称a[s:t]是a[l:r]的子序列。现在有q个询问,每个询问给定两个数l和r,1≤l≤r
≤n,求a[l:r]的不同子序列的最小值之和。例如,给定序列5,2,4,1,3,询问给定的两个数为1和3,那么a[1:3]有
6个子序列a[1:1],a[2:2],a[3:3],a[1:2],a[2:3],a[1:3],这6个子序列的最小值之和为5+2+4+2+2+2=17。
Input
输入文件的第一行包含两个整数n和q,分别代表序列长度和询问数。接下来一行,包含n个整数,以空格隔开
,第i个整数为ai,即序列第i个元素的值。接下来q行,每行包含两个整数l和r,代表一次询问。
Output
对于每次询问,输出一行,代表询问的答案。
Sample Input
5 2 4 1 3
1 5
1 3
2 4
3 5
2 5
Sample Output
17
11
11
17
HINT
1 ≤N,Q ≤ 100000,|Ai| ≤ 10^9
题解:
这道题我刚拿到手被打懵了……但其实这道题有明显的2个特征:
第一,这是区间统计类问题;第二,没要求在线
这样的话我们就考虑一些离线的区间统计算法,首先想到的大概都是莫队。
那么莫队可行吗?我们以从[l,r]转移到[l,r+1]为例,考虑每一次端点移动时带来的影响。如果这样可做,其他三种情况肯定是类似的。
在移动之后,新增了[l,r+1],[l+1,r+1],[l+2,r+1],......,[r+1,r+1]这一些区间。
我们考虑新区间最小的数,设其为a[x],那么,显然有:
从[l,r+1]到[x,r+1]这些区间的最小值都不会是a[r+1],而[x+1,r+1]到[r+1,r+1]这些区间的最小值不确定
因此当转移时,记录变量ans+=(x-l+1)*a[x]+卫龙
那么现在的问题是,卫龙是啥?怎么计算?
不难看出,卫龙指的就是从[x+1,r+1]到[r+1,r+1]这些区间的最小值之和,如果直接对它暴力计算显然不行,因此我们换一种思路。
设f[i]为以i为右端点的区间最小值之和,那么对于上面所说的r和x,由于a[x]是区间最小值,故对于
任何y<=x,区间[y,x],[y,r+1]的最小值肯定不会发生变化,而如果y>x,我们已经在f里加过了
那么显然 f[r+1]-f[x]就是我们要求的卫龙了因此得到转移的式子ans+=(x-l+1)*a[x]+f[r+1]-f[x]
而对f数组的计算可以递推处理,设a[x]为左数第一个小于a[i]的数,那么有f[i]=f[x]+(i-x)*a[i]
正确性很显然,在x以右的区间最小值一定是a[i],而由于x的性质,x及x左边的区间最小值在区间右端点右移后也不会变化
这样我们可以用一个单调栈,在O(n)的时间内计算f数组
这样,这道题就可以做了,只要再把区间左端点移动的情况考虑一下,再计算一个新的f1数组表示以i为左端点的区间最小值之和即可
代码见下:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N=;
struct quest{int id,l,r;}q[N];
int n,m,len;
int minpos[N][],bin[],belong[N],stack[N];
LL a[N],l_f[N],r_f[N],ans[N],minv[N][];
inline bool mt(const quest &a,const quest &b)
{
if(belong[a.l]==belong[b.l])return a.r<b.r;
return belong[a.l]<belong[b.l];
}
inline void intn()
{
scanf("%d%d",&n,&m);len=sqrt(n+0.5);
for(int i=;i<=n;i++)scanf("%lld",&a[i]),belong[i]=(i-)/len+;
for(int i=;i<=m;i++)q[i].id=i,scanf("%d%d",&q[i].l,&q[i].r);
sort(q+,q+m+,mt);
for(int i=;i<=n;i++)minv[i][]=a[i],minpos[i][]=i;
bin[]=;for(int i=;i<=;i++)bin[i]=bin[i-]<<;
for(int i=;bin[i]<=n;i++)
for(int j=;j+bin[i]-<=n;j++)
{
minv[j][i]=min(minv[j][i-],minv[j+bin[i-]][i-]);
if(minv[j][i]==minv[j][i-])minpos[j][i]=minpos[j][i-];
else minpos[j][i]=minpos[j+bin[i-]][i-];
}
int i,top;
for(i=,top=;i<=n;i++)
{
while(top&&a[stack[top]]>a[i])top--;
l_f[i]=l_f[stack[top]]+(i-stack[top])*a[i];
stack[++top]=i;
}
for(i=n,top=;i;i--)
{
while(top&&a[stack[top]]>=a[i])top--;
if(top)r_f[i]=r_f[stack[top]]+(stack[top]-i)*a[i];
else r_f[i]=(n-i+)*a[i];
stack[++top]=i;
}
}
inline int query(int l,int r)
{
int k=;while(bin[k]<=r-l+)k++;
k--;if(minv[l][k]<minv[r-bin[k]+][k])return minpos[l][k];
else return minpos[r-bin[k]+][k];
}
int main()
{
intn();int mpos,l=,r=;LL tmp=a[];
for(int i=;i<=m;i++)
{
while(r<q[i].r)
r++,mpos=query(l,r),tmp+=l_f[r]-l_f[mpos]+(LL)(mpos-l+)*a[mpos];
while(r>q[i].r)
mpos=query(l,r),tmp-=l_f[r]-l_f[mpos]+(LL)(mpos-l+)*a[mpos],r--;
while(l<q[i].l)
mpos=query(l,r),tmp-=r_f[l]-r_f[mpos]+(LL)(r-mpos+)*a[mpos],l++;
while(l>q[i].l)
l--,mpos=query(l,r),tmp+=r_f[l]-r_f[mpos]+(LL)(r-mpos+)*a[mpos];
ans[q[i].id]=tmp;
}
for(int i=;i<=m;i++)
printf("%lld\n",ans[i]);
}
[BZOJ4540][HNOI2016]序列 莫队的更多相关文章
- [bzoj4540][Hnoi2016][序列] (莫队算法+单调栈+st表)
Description 给定长度为n的序列:a1,a2,…,an,记为a[1:n].类似地,a[l:r](1≤l≤r≤N)是指序列:al,al+1,…,ar-1,ar.若1≤l≤s≤t≤r≤n,则称a ...
- [HNOI2016]序列(莫队,RMQ)
[HNOI2016]序列(莫队,RMQ) 洛谷 bzoj 一眼看不出来怎么用数据结构维护 然后还没修改 所以考虑莫队 以$(l,r-1) -> (l,r)$为例 对答案的贡献是$\Sigma_ ...
- 【BZOJ4540】[Hnoi2016]序列 莫队算法+单调栈
[BZOJ4540][Hnoi2016]序列 Description 给定长度为n的序列:a1,a2,…,an,记为a[1:n].类似地,a[l:r](1≤l≤r≤N)是指序列:al,al+1,…,a ...
- BZOj 4540: [Hnoi2016]序列 [莫队 st表 预处理]
4540: [Hnoi2016]序列 题意:询问区间所有子串的最小值的和 不强制在线当然上莫队啦 但是没想出来,因为不知道该维护当前区间的什么信息,维护前后缀最小值的话不好做 想到单调栈求一下,但是对 ...
- BZOJ.4540.[HNOI2016]序列(莫队/前缀和/线段树 单调栈 RMQ)
BZOJ 洛谷 ST表的一二维顺序一定要改过来. 改了就rank1了哈哈哈哈.自带小常数没办法. \(Description\) 给定长为\(n\)的序列\(A_i\).\(q\)次询问,每次给定\( ...
- bzoj 4540: [Hnoi2016]序列 莫队
题目: 给定长度为n的序列:a1,a2,-,an,记为a[1:n].类似地,a[l:r](1≤l≤r≤N)是指序列:al,al+1,-,ar- 1,ar.若1≤l≤s≤t≤r≤n,则称a[s:t]是a ...
- 洛谷P3246 [HNOI2016]序列 [莫队]
传送门 思路 看到可离线.无修改.区间询问,相信一定可以想到莫队. 然而,莫队怎么转移是个大问题. 考虑\([l,r]\rightarrow[l,r+1]\)时答案会怎样变化?(左端点变化时同理) \ ...
- BZOJ 4540 [Hnoi2016]序列 | 莫队 详细题解
传送门 BZOJ 4540 题解 --怎么说呢--本来想写线段树+矩阵乘法的-- --但是嘛--yali的机房太热了--困--写不出来-- 于是弃疗,写起了莫队.(但是我连莫队都想不出来!) 首先用单 ...
- BZOJ4540 Hnoi2016 序列 【莫队+RMQ+单调栈预处理】*
BZOJ4540 Hnoi2016 序列 Description 给定长度为n的序列:a1,a2,-,an,记为a[1:n].类似地,a[l:r](1≤l≤r≤N)是指序列:al,al+1,-,ar- ...
随机推荐
- 查看Linux系统版本的命令
1.lsb_release -a,即可列出所有版本信息: [root@S-CentOS ~]# lsb_release -a LSB Version: :base-4.0-amd64:base-4.0 ...
- 解决webstorm中测试dva项目run start命令需要不断重启问题
用dva-cli构建了项目之后在webstorm开发,用npm start跑本地服务,经常修改之后在浏览器刷新没反应,偶尔才会有刷新,需要重新跑一遍npm start才会更新,这是怎么回事呢? web ...
- 2019展望计划(Lamica 2019-Year Plan):
1,家人身体健康.2,好好上课,考试顺利,不要挂科.3,PETS3 9月份 杭州 一定要过.4,PETS3通过后,进军日语N3-N2.5,在杭州找一份合适的工作(底线6K).6,在杭州交到新朋友.7, ...
- RedHat yum源配置
RedHat yum源配置 原本以为Redhat7 和Centos7是完全一样的,可是安装完Redhat7以后,使用yum安装软件,提示红帽操作系统未注册.在网上搜索教程,最后成功解决,解决方式是将y ...
- 译 - Cassandra 数据建模的基本规则
Basic Rules of Cassandra Data Modeling 原文地址:http://www.datastax.com/dev/blog/basic-rules-of-cassandr ...
- Amazon及其亏本诱饵策略还能坚持多久?
Amazon 刚刚公布了最新的财报,亏损 4100 万美元.这是这家电子商务巨头连续 5 个季度以来的第 3 次亏损.但是华尔街似乎却一片叫好声,当日 Amazon 的股价也涨了近 8 个点达 359 ...
- ES6的新特性(12)——Set 和 Map 数据结构
Set 和 Map 数据结构 Set 基本用法 ES6 提供了新的数据结构 Set.它类似于数组,但是成员的值都是唯一的,没有重复的值. Set 本身是一个构造函数,用来生成 Set 数据结构. co ...
- 20172305 暑假作业 之 TimeCalculate & Save Iron Man
20172305 暑假作业 之 TimeCalculate & Save Iron Man TimeCalculate 项目介绍 项目名称: TimeCalculate 项目简介: 本项目基于 ...
- Programming Protocol-Independent Packet Processors
引言 OpenFlow协议固定的包头域数目,使得南向协议过于死板. P4可以实现自定义包头,增加灵活性. P4是OpenFlow未来发展的方向. We propose P4 as a strawman ...
- 【最小生成树+LCA】Imperial roads
http://codeforces.com/gym/101889 I 先跑一遍最小生成树,把经过的边和答案记录下来 对于每个询问的边,显然如果处于MST中,答案不变 如果不在MST中,假设这条边连上了 ...