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


Sample Output


HINT

1 ≤N,Q ≤ 100000,|Ai| ≤ 10^9

Solution

litc学长在暑假就讲过的题,现在临近寒假才过掉。。。

观察题目要求,容易得出若要优化暴力枚举,就要有技巧地统计每个元素产生的贡献

我们知道,任意元素x的贡献都可以表示为一个区间(l,r),其中a[l]<a[x] 且 a[r]<a[x]

询问时,我们用莫队离线做,分块一下

先按块编号和右端点下标分别为第一、第二关键字排序询问

区间最小值可以用st表预处理出来

对每个询问,我们用O(n^(1/2))时间进行转移,每次移除或加入一个元素时,统计此元素对当前区间[l,r]的贡献,算一下就行

最后输出就好了,我的程序有点慢,估计是变量名太长、函数太多

#include <math.h>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define MaxN 100010
#define MaxBuf 1<<22
#define L long long
#define RG register
#define inline __inline__ __attribute__((always_inline))
#define Blue() (S == T&&(T=(S=B)+fread(B,1,MaxBuf,stdin),S == T) ? 0 : *S++)
#define dmin(x,y) ((x) < (y)?(x):(y)) char B[MaxBuf],*S=B,*T=B; inline void Rin(RG int &x) {
x=;RG int c=Blue(),f=;
for(; c < ||c > ; c=Blue())
if(c == )f=-;
for(; c > &&c < ; c=Blue())
x=(x<<)+(x<<)+c-;
x*=f; } L sl[MaxN],sr[MaxN],ans[MaxN]; int n,m,a[MaxN],block_size,log_pre[MaxN],pl[MaxN],pr[MaxN],_pb[MaxN]; struct Pr{
int fir,sec; Pr() {} Pr(RG int _,RG int __) : fir(_),sec(__) {} bool operator < (const Pr &other) const {
return fir < other.fir; } }f[MaxN][]; struct Request{
int l,r,id,belong; bool operator < (const Request &other) const {
if(belong == other.belong)
return r < other.r;
return belong < other.belong; } }Q[MaxN]; inline void Rmq_Init() {
for(RG int i=; i<; i++)
log_pre[<<i]=;
for(RG int i=; i<=n; i++)
log_pre[i]+=log_pre[i-];
for(RG int i=; i<=n; i++)
f[i][]=Pr(a[i],i);
for(RG int k=; k<; k++)
for(RG int i=; i<=n-(<<k)+; i++)
f[i][k]=dmin(f[i][k-],f[i+(<<k-)][k-]); } inline int Rmq_Query(RG int l,RG int r) {
RG int tim=log_pre[r-l+];
return dmin(f[l][tim],f[r-(<<tim)+][tim]).sec; } inline void Mono_Stack() {
RG int top=,i;
for(i=; i<=n; i++) {
while(top && a[_pb[top]] > a[i])
pr[_pb[top]]=i,top--;
_pb[++top]=i; }
while(top)pr[_pb[top]]=n+,top--;
for(i=n; i; i--) {
while(top && a[_pb[top]] > a[i])
pl[_pb[top]]=i,top--;
_pb[++top]=i; }
while(top)pl[_pb[top]]=,top--;
for(i=; i<=n; i++)
sl[i]=sl[pl[i]]+(L)a[i]*(i-pl[i]);
for(i=n; i; i--)
sr[i]=sr[pr[i]]+(L)a[i]*(pr[i]-i);
} inline L extend(RG int l,RG int r,RG bool c) {
RG int x=Rmq_Query(l,r);
return c ? (L)a[x]*(x-l+)+sl[r]-sl[x] :
(L)a[x]*(r-x+)+sr[l]-sr[x];
} inline void block_solve() {
RG L ans;
RG int l,r,i;
for(i=; i<=m; i++) {
if(i == ||Q[i].belong != Q[i-].belong)
r=(Q[i].belong-)*block_size,l=r+,ans=;
while(r < Q[i].r)
ans+=extend(l,++r,);
while(l < Q[i].l)
ans-=extend(l++,r,);
while(l > Q[i].l)
ans+=extend(--l,r,);
:: ans[Q[i].id]=ans; } } int main() {
Rin(n),Rin(m);
block_size=static_cast<int>(sqrt(n));
for(RG int i=; i<=n; i++)
Rin(a[i]);
for(RG int i=; i<=m; i++)
Rin(Q[i].l),Rin(Q[i].r),Q[i].id=i,Q[i].belong=(Q[i].l-)/block_size+;
std::sort(Q+,Q++m); Rmq_Init();
Mono_Stack();
block_solve(); for(RG int i=; i<=m; i++)
printf("%lld\n",ans[i]);
return ; }

[bzoj4540][Hnoi2016][序列] (莫队算法+单调栈+st表)的更多相关文章

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

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

  2. [BZOJ4540][HNOI2016]序列 莫队

    4540: [Hnoi2016]序列 Time Limit: 20 Sec  Memory Limit: 512 MB Description 给定长度为n的序列:a1,a2,…,an,记为a[1:n ...

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

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

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

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

  5. BZOJ 4540 [Hnoi2016]序列 (单调栈 + ST表 + 莫队算法)

    题目链接  BZOJ4540 考虑莫队算法. 这题难在$[l, r]$到$[l, r+1]$的转移. 根据莫队算法的原理,这个时候答案应该加上 $cal(l, r+1) + cal(l+1, r+1) ...

  6. BZOJ 3809 Gty的二逼妹子序列 莫队算法+分块

    Description Autumn和Bakser又在研究Gty的妹子序列了!但他们遇到了一个难题. 对于一段妹子们,他们想让你帮忙求出这之内美丽度∈[a,b]的妹子的美丽度的种类数. 为了方便,我们 ...

  7. 【bzoj4542】[Hnoi2016]大数 莫队算法

    题目描述 给出一个数字串,多次询问一段区间有多少个子区间对应的数为P的倍数.其中P为质数. 输入 第一行一个整数:P.第二行一个串:S.第三行一个整数:M.接下来M行,每行两个整数 fr,to,表示对 ...

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

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

  9. bzoj 4540 [HNOI 2016] 序列 - 莫队算法 - Sparse-Table - 单调栈

    题目传送门 传送点I 传送点II 题目大意 给定一个长度为$n$的序列.询问区间$[l, r]$的所有不同的子序列的最小值的和. 这里的子序列是连续的.两个子序列不同当且仅当它们的左端点或右端点不同. ...

随机推荐

  1. SQL实现多行合并一行 .

    ORACLE纯SQL实现多行合并一行[转] 项目中遇到一个需求,需要将多行合并为一行.表结构如下:NAME                            Null           Type ...

  2. jQueryRotate 转盘抽奖代码实现

    代码如下: 例子兼容IE6,7,8 以及高版本浏览器,如有bug请回复! 1.html结构 <!doctype html> <html lang="en"> ...

  3. SQL Server查看表结构及视图,适合开发者使用,简单易用

    SELECT * FROM INFORMATION_SCHEMA.TABLES SELECT * FROM INFORMATION_SCHEMA.COLUMNS 查看执行结果

  4. iOS基础 - 多线程线程

    一.多线程的应用 l 充分发挥多核处理器的优势,并发(同时执行)执行任务让系统运行的更快.更流畅 二.进程与线程概念 l 一个运行的程序就是一个进程或者叫做一个任务 l 一个进程至少包含一个线程,线程 ...

  5. Bootstrap3.0学习第八轮

    Bootstrap3.0学习第八轮(工具Class)   前言 阅读之前您也可以到Bootstrap3.0入门学习系列导航中进行查看http://www.cnblogs.com/aehyok/p/34 ...

  6. [转]Mac's and serial TTY's

    Mac's are excellent tools for accessing serial device TTY ports (to console into PBX's, switches, an ...

  7. C# BackgroundWorker组件学习

    C# BackgroundWorker组件学习  C# BackgroundWorker组件学习 一个程序中需要进行大量的运算,并且需要在运算过程中支持用户一定的交互,为了获得更好的用户体验,使用Ba ...

  8. Django 源码小剖: 初探 WSGI

    Django 源码小剖: 初探 WSGI python 作为一种脚本语言, 已经逐渐大量用于 web 后台开发中, 而基于 python 的 web 应用程序框架也越来越多, Bottle, Djan ...

  9. Changing the working directory of VIM

    Sometimes we want to open another file in the same folder with current editing file, what we can do ...

  10. Atomic变量和Thread局部变量

    Atomic变量和Thread局部变量 前面我们已经讲过如何让对象具有Thread安全性,让它们能够在同一时间在两个或以上的Thread中使用.Thread的安全性在多线程设计中非常重要,因为race ...