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 5
5 2 4 1 3
1 5
1 3
2 4
3 5
2 5

Sample Output

28
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]序列 莫队的更多相关文章

  1. [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 ...

  2. [HNOI2016]序列(莫队,RMQ)

    [HNOI2016]序列(莫队,RMQ) 洛谷  bzoj 一眼看不出来怎么用数据结构维护 然后还没修改 所以考虑莫队 以$(l,r-1) -> (l,r)$为例 对答案的贡献是$\Sigma_ ...

  3. 【BZOJ4540】[Hnoi2016]序列 莫队算法+单调栈

    [BZOJ4540][Hnoi2016]序列 Description 给定长度为n的序列:a1,a2,…,an,记为a[1:n].类似地,a[l:r](1≤l≤r≤N)是指序列:al,al+1,…,a ...

  4. BZOj 4540: [Hnoi2016]序列 [莫队 st表 预处理]

    4540: [Hnoi2016]序列 题意:询问区间所有子串的最小值的和 不强制在线当然上莫队啦 但是没想出来,因为不知道该维护当前区间的什么信息,维护前后缀最小值的话不好做 想到单调栈求一下,但是对 ...

  5. BZOJ.4540.[HNOI2016]序列(莫队/前缀和/线段树 单调栈 RMQ)

    BZOJ 洛谷 ST表的一二维顺序一定要改过来. 改了就rank1了哈哈哈哈.自带小常数没办法. \(Description\) 给定长为\(n\)的序列\(A_i\).\(q\)次询问,每次给定\( ...

  6. 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 ...

  7. 洛谷P3246 [HNOI2016]序列 [莫队]

    传送门 思路 看到可离线.无修改.区间询问,相信一定可以想到莫队. 然而,莫队怎么转移是个大问题. 考虑\([l,r]\rightarrow[l,r+1]\)时答案会怎样变化?(左端点变化时同理) \ ...

  8. BZOJ 4540 [Hnoi2016]序列 | 莫队 详细题解

    传送门 BZOJ 4540 题解 --怎么说呢--本来想写线段树+矩阵乘法的-- --但是嘛--yali的机房太热了--困--写不出来-- 于是弃疗,写起了莫队.(但是我连莫队都想不出来!) 首先用单 ...

  9. BZOJ4540 Hnoi2016 序列 【莫队+RMQ+单调栈预处理】*

    BZOJ4540 Hnoi2016 序列 Description 给定长度为n的序列:a1,a2,-,an,记为a[1:n].类似地,a[l:r](1≤l≤r≤N)是指序列:al,al+1,-,ar- ...

随机推荐

  1. 解析hdr图像文件的python实现

    如题 import cv2 import numpy as np def rgbe2float(rgbe): res = np.zeros((rgbe.shape[0],rgbe.shape[1],3 ...

  2. JS Windows.document对象

    四中选择器:class ,id , name , 标签 通过选择器获取对象: ...................................ClassName('');  -- class选择 ...

  3. Jmeter接口测试(三)接口测试实践

    Jmeter 脚本编写一般分五个步骤: 1. 添加线程组 2. 添加 http 请求 3. 在 http 请求中写入接入 url.路径.请求方式和参数 4. 添加查看结果树 5. 调用接口.查看返回值 ...

  4. Jupyter 安装并配置工作路径[转]

    1.通过python的pip方式安装jupyterpython和pip都安装好后,通过cmd进入命令提示窗口,找到python安装目录下的Script目录,例如我的是路径是:C:\Program Fi ...

  5. 【坚持】Selenium+Python学习之从读懂代码开始 DAY1

    学习Selenium+Python已经好几个月了,但越学发现不懂的东西越多. 感觉最大的问题还是在于基础不扎实,决定从头开始,每天坚持读代码,写代码. 相信量变一定能到质变!!! 2018/05/09 ...

  6. MapPartition和Map的区别

    在Spark中有map和mapPartitions算子,处理数据上,有一些区别 主要区别: map是对rdd中的每一个元素进行操作: mapPartitions则是对rdd中的每个分区的迭代器进行操作 ...

  7. 宿主机ssh免密登录docker容器

    一.检查系统内核 二.安装docker 1.yum install docker  -y 2.docker version                    #查看docker版本 3.syste ...

  8. centos 7 install gnome etc

    centos yum 有grouplist子命令,可以查看当前系统有多少软件组件,里面就有gnome:"GNOME Desktop" sudo yum groupinstall G ...

  9. ASP.NET Web API - 使用 Castle Windsor 依赖注入

    示例代码 项目启动时,创建依赖注入容器 定义一静态容器 IWindsorContainer private static IWindsorContainer _container; 在 Applica ...

  10. 7. B+树

    一.B+树是应文件系统所需而产生的一种B树的变形树 1. 定义(使用阶数m来定义) 除了根结点外,其他非终端结点最多有m个关键字,最少有⌈m/2⌉个关键字 结点中的每个关键字对应一个子树 所有的非终端 ...