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. springboot对security的后端配置

    一.Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架.它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring ...

  2. (转) 理解Angular中的$apply()以及$digest()

    原文地址:http://blog.csdn.net/dm_vincent/article/details/38705099 $apply()和$digest()在AngularJS中是两个核心概念,但 ...

  3. Azkaban 工作流调度器

    Azkaban 工作流调度器 1 概述 1.1 为什么需要工作流调度系统 a)一个完整的数据分析系统通常都是由大量任务单元组成,shell脚本程序,java程序,mapreduce程序.hive脚本等 ...

  4. L018-课前练习以及知识巩固笔记

    L018-课前练习以及知识巩固笔记 OK,今天课前做了几道题,算是对以往知识的巩固. 1.请描述下列路径的内容是做什么的?/etc/sysctl.conf/etc/rc.local/etc/hosts ...

  5. stl源码分析之priority queue

    前面两篇介绍了gcc4.8的vector和list的源码实现,这是stl最常用了两种序列式容器.除了容器之外,stl还提供了一种借助容器实现特殊操作的组件,谓之适配器,比如stack,queue,pr ...

  6. throttle(节流)和debounce(防抖)

    防抖和节流都是用来控制频繁调用的问题,但是这两种的应用场景是有区别的. throttle(节流) 有一个调用周期,在一个很长的时间里分为多段,每一段执行一次.例如onscroll,resize,500 ...

  7. 最大公共子串:DP

    标题:最大公共子串 最大公共子串长度问题就是:求两个串的所有子串中能够匹配上的最大长度是多少. 比如:"abcdkkk" 和 "baabcdadabc",可以找 ...

  8. [T-ARA][Falling U]

    歌词来源:http://music.163.com/#/song?id=27506041 作词:韩尚元 [作词:韩尚元] 作曲:韩尚元 [作曲:韩尚元] Love is pain Love is pa ...

  9. 根据Unicode码生成汉字

    最近需要一批汉字字符数据,类似数字字符与ASCII码之间的对应关系,汉字字符与Unicode码之间也存在对应关系. 所以可以遍历Unicode码批量生成汉字. 其中,汉字为宽字符,输出时候注意需要修改 ...

  10. mysql常用语句入门整理

    这篇属于小白入门级别,如果你已经高手可以直接跳过 1.运行数据库mysqld.exe,客户端直接mysql -uroot(root是默认用户名) -p 2 showdatabases,showtabl ...