BZOJ4540 [Hnoi2016]序列
本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作。
本文作者:ljh2000
作者博客:http://www.cnblogs.com/ljh2000-jump/
转载请注明出处,侵权必究,保留最终解释权!
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
正解:莫队算法$+ST$表$+$单调栈。
解题报告:
这题可以用莫队算法来做。
莫队算法的关键在于如何计算贡献:当我对于区间$[l,r-1]$加入$r$时,会产生$(r-l+1)$个子串,也就会产生这么多新的贡献,接下来我们只考虑这些新贡献。
令$[l,r]$的最小值所在位置为$t$,则容易发现t能产生的贡献为$(t-l+1)*a[t]$;
对于$r$能产生的贡献,不妨设$last[r]$为$r$的左边比$r$小的第一个元素的位置($last$数组显然可以用单调栈$O(n)$的求出),则$r$的贡献为$(r-last[r])*a[r]$,以此类推,$last[r]$的贡献为$(last[r]-last[last[r]])*a[last[r]]$。
那么我们可以根据上式构造出一个类似于前缀和的东西,令$suml[r]$表示r一直按上述操作走到0的每个点的贡献之和,则可以用$suml[r]=suml[last[r]]+(r-last[r])*a[r]$进行递推。这样一来我可以在$O(1)$的时间里面完成对$r$加入所产生的贡献的影响。
而$r$删除是等价的,只要变成减去就可以了。至于$l$的情况,完全类似。
有一些需要注意的地方:相等的时候取左边,记得开$long$ $long$,单调栈最后栈内的元素需要另外处理!
//It is made by ljh2000
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <ctime>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <string>
using namespace std;
typedef long long LL;
const int MAXN = 100011;
int n,m,belong[MAXN],ST[MAXN][18],l,r;
int last[MAXN],next[MAXN],stack[MAXN],top,block;
LL suml[MAXN],sumr[MAXN],A[MAXN],ans,a[MAXN];
struct ask{int l,r,id,lb;}q[MAXN];
inline bool cmp(ask q,ask qq){ if(q.lb==qq.lb) return q.r<qq.r; return q.lb<qq.lb; }
inline int getint(){
int w=0,q=0; char c=getchar(); while((c<'0'||c>'9') && c!='-') c=getchar();
if(c=='-') q=1,c=getchar(); while (c>='0'&&c<='9') w=w*10+c-'0',c=getchar(); return q?-w:w;
} inline int query(int l,int r){
int t=belong[r-l+1],cc=r-(1<<t)+1;
if(a[ST[l][t]]<=a[ST[cc][t]]) return ST[l][t];
return ST[cc][t];
} inline void updatel(int l,int r,int type){
int from=query(l,r); LL suan=(r-from+1)*a[from]/*!!!*/;
suan+=sumr[l]-sumr[from]; ans+=type*suan;
} inline void updater(int l,int r,int type){
int from=query(l,r); LL suan=(from-l+1)*a[from]/*!!!*/;
suan+=suml[r]-suml[from]; ans+=type*suan;
} inline void work(){
n=getint(); m=getint(); for(int i=1;i<=n;i++) a[i]=getint(),ST[i][0]=i; block=sqrt(n);
for(int i=1;i<=m;i++) q[i].l=getint(),q[i].r=getint(),q[i].id=i,q[i].lb=(q[i].l-1)/block+1;
sort(q+1,q+m+1,cmp); int from;
belong[1]=0; for(int i=2;i<=n;i++) belong[i]=belong[i>>1]+1; a[0]=(1<<30);
for(int j=1;j<=17;j++)
for(int i=1;i<=n;i++) {
from=i+(1<<(j-1));
if(from<=n && a[ST[i][j-1]]<=a[ST[from][j-1]]) ST[i][j]=ST[i][j-1];
else ST[i][j]=ST[from][j-1];
}
top=0; stack[0]=0;
for(int i=1;i<=n;i++) {
while(top>0 && a[i]<a[stack[top]]) next[stack[top]]=i,top--;
last[i]=stack[top]; stack[++top]=i;
}
while(top>0) next[stack[top]]=n+1,top--;
for(int i=1;i<=n;i++) suml[i]=suml[last[i]]+(LL)(i-last[i])*a[i];
for(int i=n;i>=1;i--) sumr[i]=sumr[next[i]]+(LL)(next[i]-i)*a[i];
ans=a[1]; l=r=1;
for(int i=1;i<=m;i++) {
while(r<q[i].r) r++,updater(l,r,1);
while(l>q[i].l) l--,updatel(l,r,1);
while(r>q[i].r) updater(l,r,-1),r--;
while(l<q[i].l) updatel(l,r,-1),l++;
A[q[i].id]=ans;
}
for(int i=1;i<=m;i++) printf("%lld\n",A[i]);
} int main()
{
work();
return 0;
}
BZOJ4540 [Hnoi2016]序列的更多相关文章
- BZOJ4540 Hnoi2016 序列 【莫队+RMQ+单调栈预处理】*
BZOJ4540 Hnoi2016 序列 Description 给定长度为n的序列:a1,a2,-,an,记为a[1:n].类似地,a[l:r](1≤l≤r≤N)是指序列:al,al+1,-,ar- ...
- [BZOJ4540][HNOI2016]序列 莫队
4540: [Hnoi2016]序列 Time Limit: 20 Sec Memory Limit: 512 MB Description 给定长度为n的序列:a1,a2,…,an,记为a[1:n ...
- [Bzoj4540][Hnoi2016] 序列(莫队 + ST表 + 单调队列)
4540: [Hnoi2016]序列 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 1567 Solved: 718[Submit][Status] ...
- [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 ...
- [luogu3246][bzoj4540][HNOI2016]序列【莫队+单调栈】
题目描述 给定长度为n的序列:a1,a2,...,an,记为a[1:n].类似地,a[l:r](1<=l<=r<=N)是指序列:al,al+1,...,ar-1,ar.若1<= ...
- BZOJ4540 [Hnoi2016]序列 【莫队 + ST表 + 单调栈】
题目 给定长度为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[ ...
- 【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]序列 题意:询问区间所有子串的最小值的和 不强制在线当然上莫队啦 但是没想出来,因为不知道该维护当前区间的什么信息,维护前后缀最小值的话不好做 想到单调栈求一下,但是对 ...
- 【LG3246】[HNOI2016]序列
[LG3246][HNOI2016]序列 题面 洛谷 题解 60pts 对于每个位置\(i\),单调栈维护它往左第一个小于等于它的位置\(lp_i\)以及往右第一个小于它的位置\(rp_i\). 那么 ...
随机推荐
- 基于Flume+LOG4J+Kafka的日志采集架构方案
本文将会介绍如何使用 Flume.log4j.Kafka进行规范的日志采集. Flume 基本概念 Flume是一个完善.强大的日志采集工具,关于它的配置,在网上有很多现成的例子和资料,这里仅做简单说 ...
- 基于nutz框架理解Ioc容器
同样我们从问题入手去验证以及去理解Ioc容器都做了哪些事情: 1.nutz是有几种方式获取需要容器管理bean的信息? 第一种是使用json格式的文件进行配置,如: 第二种:使用注解@IocBean ...
- C# Attribute学习
由于项目中需要使用到序列化相关的技术,从而想到是否可以使用C#中的特性,特此花了近两小时学习了一下. 对于特性的学习,主要参考了两篇博文,特此感谢.以下附链接: http://www.cnblogs. ...
- 大型web系统数据缓存设计
1. 前言 在高访问量的web系统中,缓存几乎是离不开的:但是一个适当.高效的缓存方案设计却并不容易:所以接下来将讨论一下应用系统缓存的设计方面应该注意哪些东西,包括缓存的选型.常见缓存系统的特点和数 ...
- 穿越之旅之--android中如何执行java命令
android的程序基于java开发,当我们接上调试器,执行adb shell,就可以执行linux命令,但是却并不能执行java命令. 那么在android的shell中是否就不能执行java程序了 ...
- ::before和::after伪元素的用法
一.介绍 css3为了区分伪类和伪元素,伪元素采用双冒号写法. 常见伪类——:hover,:link,:active,:target,:not(),:focus. 常见伪元素——::first-let ...
- Oracle体系结构详解
对于一门技术的学习,尤其是像Oracle database这种知识体系极其庞杂的技术来讲,从宏观上了解其体系结构是至关重要的.同时,个人认为,未必是专业DBA人员才需要了解其体系结构(固然对于数据库专 ...
- 【原】移动web页面支持弹性滚动的3个方案
有段时间一直折腾移动端页面弹性滚动的各种问题,做了点研究,今天做个小分享~ 传统 pc 端中,子容器高度超出父容器高度,通常使用 overflow:auto 可出现滚动条拖动显示溢出的内容,而移动we ...
- JS入门学习,写一个简单的选项卡
/* 经过昨天一整天的纠结和摸索.总结下学习初期我最致命的几个问题…… 1.var oDiv = document.getElementById(''); 一定要多输,熟悉后o u什么的字母别搞 ...
- 【读书笔记《Bootstrap 实战》】6.单页营销网站
我们已经掌握了很多实用 Bootstrap 的重要技能.现在,是时候拿出更多的创意来帮助客户实现他们全方位在线营销的愿望了.此次将带领大家做一个漂亮的单页高端营销网站. 主要任务如下: □ 一个大型 ...