『序列 莫队 dp预处理』
<更新提示>
<第一次更新>
<正文>
序列
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 Format
输入文件的第一行包含两个整数n和q,分别代表序列长度和询问数。
接下来一行,包含n个整数,以空格隔开,第i个整数为ai,即序列第i个元素的值。
接下来q行,每行包含两个整数l和r,代表一次询问。
Output Format
对于每次询问,输出一行,代表询问的答案。
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
解析
回答若干个静态的区间询问,思路是莫队。
假设我们已经得到了区间\([l,r]\)的答案,直接考虑如何转移到\([l,r+1]\)。显然,我们只需要考虑包含\(r+1\)这一个点的子序列\([l,r+1],[l+1,r+1],...,[r+1,r+1]\)即可。要求的是最小值之和,我们就设\([l,r+1]\)在\(a\)序列上的区间最小值为\(a_p\),位置是\(p\),那么所有左端点在\([l,p]\)之间的区间的答案就都是\(a_p\),总共的贡献为\(a_p*(p-l+1)\),这个问题显然可以用\(ST\)表解决。
那么剩下的那些区间我们考虑用\(dp\)来计算答案。设\(f[i][j]\)代表右端点为\(j\),左端点在\([i,j]\)之间的答案之和,那么我们要求的就是\(f[p+1][r+1]\)。记录下\(prep_i\)代表\(a\)序列中\(a_i\)左边第一个比他小的元素的位置(单调栈解决),状态转移方程就是:$$f[i][j]=f[i][prep_j]+a_j*(j-prep_j)$$。
发现状态转移方程与\(i\)无关,直接将第一维舍去,那么\(f[j]\)的定义就是右端点为\(j\)的所有区间的答案之和。继续考虑原问题,发现必然存在一个点\(x\)满足\(prep_x=p\),\(f[r+1]=a_{r+1}*(r+1-prep_{r+1})+...+a_x*(x-p)+f[p]\),那么我们原来要求的\(f[p+1][r+1]\)其实可以表示为\(f[r+1]-f[p]\),然后预处理出\(f\)数组,就可在莫队当中\(O(1)\)转移了。
当然,我们还需要处理出反方向的\(f\)数组,以便莫队向左转移。如果是删除操作的话,就减去加入这个点的时候带来的贡献即可。
\(Code:\)
#include <bits/stdc++.h>
using namespace std;
const int N = 100200 , MaxlogN = 25 , INF = 2e9;
int n,m,a[N],size;
int Min[N][MaxlogN],Log2[N],Pow2[MaxlogN];
int prep[N],next[N],Stack[N],top;
long long ans[N],fl[N],fr[N],tot;
struct Query{int l,r,id;}q[N];
inline void init(void)
{
Pow2[0] = 1 , a[0] = a[n+1] = INF;
for (int i=1;i<=MaxlogN-2;i++)
Pow2[i] = Pow2[i-1] << 1;
for (int i=2;i<=n;i++)
Log2[i] = Log2[i>>1] + 1;
for (int i=1;i<=n;i++)
Min[i][0] = i;
for (int k=1;k<=Log2[n];k++)
for (int i=1;i+Pow2[k-1]-1<=n;i++)
if ( a[ Min[i][k-1] ] < a[ Min[i+Pow2[k-1]][k-1] ] )
Min[i][k] = Min[i][k-1];
else Min[i][k] = Min[i+Pow2[k-1]][k-1];
top = 0;
for (int i=1;i<=n;i++)
{
while ( top && a[Stack[top]] > a[i] )
next[ Stack[top--] ] = i;
prep[i] = Stack[top] ; Stack[++top] = i;
}
while ( top )
{
prep[ Stack[top] ] = Stack[top-1];
next[ Stack[top] ] = n+1;
top--;
}
}
inline int query(int l,int r)
{
int k = Log2[r-l+1];
if ( a[ Min[l][k] ] < a[ Min[r-Pow2[k]+1][k] ] )
return Min[l][k];
else return Min[r-Pow2[k]+1][k];
}
inline void input(void)
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
scanf("%d",&a[i]);
for (int i=1;i<=m;i++)
scanf("%d%d",&q[i].l,&q[i].r) , q[i].id = i;
}
inline void dp(void)
{
for (int i=1;i<=n;i++)
fr[i] = fr[prep[i]] + 1LL * a[i] * (i-prep[i]);
for (int i=n;i>=1;i--)
fl[i] = fl[next[i]] + 1LL * a[i] * (next[i]-i);
}
inline bool compare(Query p1,Query p2)
{
if ( (p1.l/size) ^ (p2.l/size) )
return p1.l < p2.l ;
else if ( (p1.l/size) & 1 )
return p1.r < p2.r ;
else return p1.r > p2.r ;
}
inline void insert1(int l,int r)
{
int p = query(l,r);
tot += ( 1LL * a[p] * (p-l+1) + fr[r] - fr[p] );
}
inline void insert2(int l,int r)
{
int p = query(l,r);
tot += ( 1LL * a[p] * (r-p+1) + fl[l] - fl[p] );
}
inline void remove1(int l,int r)
{
int p = query(l,r);
tot -= ( 1LL * a[p] * (p-l+1) + fr[r] - fr[p] );
}
inline void remove2(int l,int r)
{
int p = query(l,r);
tot -= ( 1LL * a[p] * (r-p+1) + fl[l] - fl[p] );
}
inline void CaptainMo(void)
{
double val = sqrt(1.0*m*2/3);
if ( val > n || val < 500 ) size = sqrt(n);
else size = n * 1.0 / val;
sort( q+1 , q+m+1 , compare );
int l = 1 , r = 0;
for (int i=1;i<=m;i++)
{
int ql = q[i].l , qr = q[i].r;
while ( l > ql ) insert2(--l,r);
while ( r < qr ) insert1(l,++r);
while ( l < ql ) remove2(l++,r);
while ( r > qr ) remove1(l,r--);
ans[ q[i].id ] = tot;
}
}
int main(void)
{
input();
init();
dp();
CaptainMo();
for (int i=1;i<=m;i++)
printf("%lld\n",ans[i]);
return 0;
}
<后记>
『序列 莫队 dp预处理』的更多相关文章
- 学习笔记——不带修序列莫队 (luogu2079)小B的询问
莫队是一种对于询问的离线算法 时间复杂度:O(\(n \sqrt n\)) 大致思想就是 首先将询问离线,然后对原序列分块,使得每一个\(l和r\)都在一个块里 然后按照左节点排序,若所在的块相等,就 ...
- [HNOI2016]序列(莫队,RMQ)
[HNOI2016]序列(莫队,RMQ) 洛谷 bzoj 一眼看不出来怎么用数据结构维护 然后还没修改 所以考虑莫队 以$(l,r-1) -> (l,r)$为例 对答案的贡献是$\Sigma_ ...
- BZOj 4540: [Hnoi2016]序列 [莫队 st表 预处理]
4540: [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 ...
- BZOJ.4540.[HNOI2016]序列(莫队/前缀和/线段树 单调栈 RMQ)
BZOJ 洛谷 ST表的一二维顺序一定要改过来. 改了就rank1了哈哈哈哈.自带小常数没办法. \(Description\) 给定长为\(n\)的序列\(A_i\).\(q\)次询问,每次给定\( ...
- bzoj 4540 [HNOI 2016] 序列 - 莫队算法 - Sparse-Table - 单调栈
题目传送门 传送点I 传送点II 题目大意 给定一个长度为$n$的序列.询问区间$[l, r]$的所有不同的子序列的最小值的和. 这里的子序列是连续的.两个子序列不同当且仅当它们的左端点或右端点不同. ...
- 【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]序列 莫队
题目: 给定长度为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 ...
- Bzoj 3809: Gty的二逼妹子序列 莫队,分块
3809: Gty的二逼妹子序列 Time Limit: 35 Sec Memory Limit: 28 MBSubmit: 868 Solved: 234[Submit][Status][Dis ...
随机推荐
- Centos7下安装redis并能使得外网访问
一.安装脚本 #!/bin/bash #FileName: install_redis_centos7.sh #Date: #Author: LiLe #Contact: @qq.com #Versi ...
- Python的字符串与字节码转换
一张图弄懂python的字符串与字节码转换
- 超强的Lambda Stream流操作
原文:https://www.cnblogs.com/niumoo/p/11880172.html 在使用 Stream 流操作之前你应该先了解 Lambda 相关知识,如果还不了解,可以参考之前文章 ...
- Java期末复习——主观题
JDK 和 JRE 有什么区别? JDK:Java Development Kit 的简称,java 开发工具包,提供了 java 的开发环境和运行环境. JRE:Java Runtime Envir ...
- 十大排序算法总结(Python3实现)
十大排序算法总结(Python3实现) 本文链接:https://blog.csdn.net/aiya_aiya_/article/details/79846380 目录 一.概述 二.算法简介及代码 ...
- Python学习笔记7 头文件的添加规则(转载)
转载自:https://www.cnblogs.com/taurusfy/p/7605787.html ************************************************ ...
- 达信:深度解读COSO新版企业风险管理框架(ERM)
http://www.sohu.com/a/124375769_489979 2016年6月,美国反欺诈财务报告委员会(The Committee of Sponsoring Organization ...
- 使用面向对象思想封装js(附实例)
平时在写js时应该用面向对象思想将每一组功能封装成一个模块,可实现模块间的高内聚低耦合.重用.结构清晰........... 如果页面中逻辑复杂.功能多,不使用模块封装是不可想象的,维护起来非常复杂. ...
- Java的静态变量初始化的坑
在网上看到一个很有意思的题目,题目如下 class SingleTon { private static SingleTon singleTon = new SingleTon(); public s ...
- nuxt或者vue,axios中如何发送多个请求
在使用vue或者nuxt中,我们需要使用axios去发送多个http请求,参考了axios的官方说明你也许会想到使用axios.all发送请求,但是这样可能会出现一些异常错误: (node:9360) ...