题目

  给定长度为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。

输入格式

  输入文件的第一行包含两个整数n和q,分别代表序列长度和询问数。接下来一行,包含n个整数,以空格隔开

,第i个整数为ai,即序列第i个元素的值。接下来q行,每行包含两个整数l和r,代表一次询问。

输出格式

  对于每次询问,输出一行,代表询问的答案。

输入样例

5 5

5 2 4 1 3

1 5

1 3

2 4

3 5

2 5

输出样例

28

17

11

11

17

提示

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

题解

考虑莫队

我们只需要考虑如何\(O(1)\)扩展区间即可

扩展左右端点是类似的

以右端点为例

新产生的子区间一定是以新的右端点\(r\)为右端点的那些子区间

那么考虑所有左端点产生的影响

从区间最小值的位置到区间左端点,左端点在这个区间内的贡献一定是区间最小值

至于左端点在右半区间时产生的贡献,我们再考虑:

从\(r\)一直到一个比\(A[r]\)小的位置\(pos\),答案一直是\(A[r]\)

然后从\(pos\)开始,向左一直到一个比\(A[pos]\)小的位置,答案一直是\(A[pos]\)

一次类推

如果将每个位置向往前第一个比它小的位置连边,这就是一个树结构,我们只用\(O(1)\)求出树链两点距离即可解决右半区间的答案

建树可以用单调栈实现

我们再用\(ST\)表维护最小值就可以做到\(O(1)\)扩展区间了

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define LL long long int
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<' '; puts("");
using namespace std;
const int maxn = 100005,maxm = 100005,INF = 1000000000;
inline int read(){
int out = 0,flag = 1; char c = getchar();
while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
return out * flag;
}
int h[maxn],ne = 1;
struct EDGE{int to,nxt;}ed[maxn];
inline void build(int u,int v){
ed[ne] = (EDGE){v,h[u]}; h[u] = ne++;
}
LL Ls[maxn],Rs[maxn];
LL mn[maxn][18],n,Q,A[maxn],fa[maxn],fa1[maxn],bin[30],Log[maxn],B;
LL st[maxn],top,vis[maxn];
void dfs1(int u){
vis[u] = true;
if (fa[u]) Ls[u] = Ls[fa[u]] + (u - fa[u]) * A[u];
Redge(u) {
fa[to = ed[k].to] = u;
dfs1(to);
}
}
void dfs2(int u){
vis[u] = true;
if (fa1[u]) Rs[u] = Rs[fa1[u]] + (fa1[u] - u) * A[u];
Redge(u) {
fa1[to = ed[k].to] = u;
dfs2(to);
}
}
void init(){
REP(j,17) REP(i,n){
if (i + bin[j] - 1 > n) break;
mn[i][j] = A[mn[i][j - 1]] <= A[mn[i + bin[j - 1]][j - 1]] ? mn[i][j - 1] : mn[i + bin[j - 1]][j - 1];
}
REP(i,n){
while (top && A[st[top]] > A[i]) top--;
if (top) build(st[top],i);
st[++top] = i;
}
REP(i,n) if (!vis[i]) fa[i] = 0,dfs1(i);
top = 0; memset(vis,0,sizeof(vis)); memset(h,0,sizeof(h)); ne = 1;
for (int i = n; i; i--){
while (top && A[st[top]] > A[i]) top--;
if (top) build(st[top],i);
st[++top] = i;
}
for (int i = n; i; i--) if (!vis[i]) fa1[i] = 0,dfs2(i);
}
int getmn(int l,int r){
int t = Log[r - l + 1];
return A[mn[l][t]] <= A[mn[r - bin[t] + 1][t]] ? mn[l][t] : mn[r - bin[t] + 1][t];
}
struct Que{int l,r,id,b;}q[maxn];
LL ans[maxn];
inline bool operator <(const Que& a,const Que& b){
return a.b == b.b ? a.r < b.r : a.l < b.l;
}
void solve(){
sort(q + 1,q + 1 + Q);
LL tot = 0,L = q[1].l,R = q[1].r,pos;
for (int i = L; i <= R; i++){
pos = getmn(L,i);
if (A[pos] == A[i]) tot += (i - L + 1) * A[i];
else tot += (pos - L + 1) * A[pos] + Ls[i] - Ls[pos];
}
ans[q[1].id] = tot;
for (int i = 2; i <= Q; i++){
while (L != q[i].l || R != q[i].r){
if (L > q[i].l){
L--;
pos = getmn(L,R);
if (A[pos] == A[L]) tot += (R - L + 1) * A[L];
else tot += (R - pos + 1) * A[pos] + Rs[L] - Rs[pos];
}
if (L < q[i].l){
pos = getmn(L,R);
if (A[pos] == A[L]) tot -= (R - L + 1) * A[L];
else tot -= (R - pos + 1) * A[pos] + Rs[L] - Rs[pos];
L++;
}
if (R < q[i].r){
R++;
pos = getmn(L,R);
if (A[pos] == A[R]) tot += (R - L + 1) * A[R];
else tot += (pos - L + 1) * A[pos] + Ls[R] - Ls[pos];
}
if (R > q[i].r){
pos = getmn(L,R);
if (A[pos] == A[R]) tot -= (R - L + 1) * A[R];
else tot -= (pos - L + 1) * A[pos] + Ls[R] - Ls[pos];
R--;
}
}
ans[q[i].id] = tot;
}
REP(i,Q) printf("%lld\n",ans[i]);
}
int main(){
bin[0] = 1; for (int i = 1; i <= 25; i++) bin[i] = bin[i - 1] << 1;
Log[0] = -1; for (int i = 1; i < maxn; i++) Log[i] = Log[i >> 1] + 1;
n = read(); Q = read();
REP(i,n) A[i] = read(),mn[i][0] = i;
init();
B = (int)sqrt(n) + 1;
REP(i,Q){
q[i].l = read(); q[i].r = read(); q[i].id = i; q[i].b = q[i].l / B;
}
solve();
return 0;
}

BZOJ4540 [Hnoi2016]序列 【莫队 + ST表 + 单调栈】的更多相关文章

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

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

  2. [Bzoj4540][Hnoi2016] 序列(莫队 + ST表 + 单调队列)

    4540: [Hnoi2016]序列 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1567  Solved: 718[Submit][Status] ...

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

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

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

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

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

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

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

  7. [多校联考2019(Round 4 T2)][51nod 1288]汽油补给(ST表+单调栈)

    [51nod 1288]汽油补给(ST表+单调栈) 题面 有(N+1)个城市,0是起点N是终点,开车从0 -> 1 - > 2...... -> N,车每走1个单位距离消耗1个单位的 ...

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

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

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

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

随机推荐

  1. python_17_数据运算

    #//取整除,返回商的整数部分 print(9//2) print(10/3.3) print(10//3.0) #<>与!=都为不等于 #and 与 例(a and b) #or 或 # ...

  2. SpringBoot学习记录(二)

    一. SpringBoot日志框架 SpringBoot:底层是Spring框架,Spring框架默认是用JCL(commons-logging): SpringBoot选用SLF4j和logback ...

  3. Bootstrap 警告框(Alert)插件

    警告消息大多来是用来向终端用户提示警告或确认的消息,使用警告框插件,您可以向所有的警告框消息添加取消功能. 用法 您有以下两种方式启用警告框的可取消功能. 1.通过data属性:通过数据添加可取消功能 ...

  4. Bootstrap历练实例:popover插件中的方法

    方法 下面是一些弹出框(Popover)插件中有用的方法: 方法 描述 实例 Options: .popover(options) 向元素集合附加弹出框句柄. $().popover(options) ...

  5. ES6 Reflect使用笔记

    Reflect Reflect 对象和Proxy对象一样, 为操作对象提供了新的API. 为什么使用 Reflect的方式来操作对象? 将 Object 对象上一些明显属于内部的方法放到 Reflec ...

  6. node.js express环境下中文需要注意的地方

    问题一: 最近在nuxt项目中开始着手把一些跨域的请求转移到express里,其实跟其他语言差不多,http对象发请求,接收请求都写得很顺畅.之前用的请求部分大多数是get请求,所以除了注意编码问题之 ...

  7. Girls and Boys-hdu 1068

    Girls and Boys Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) ...

  8. A1012 The Best Rank (25)(25 分)

    A1012 The Best Rank (25)(25 分) To evaluate the performance of our first year CS majored students, we ...

  9. 1、python的基础

    一.python组成 python程序的内容主要由变量.数据.关键字.操作符组成. 二.变量 在python中,变量指的是其指向的数据是可变的. 首先我们要了解一下python的内存管理.数据创建后就 ...

  10. Kubernetes添加带Quota限额的CephFS StorageClass

    1. 在Ceph上为Kubernetes创建一个文件系统 # ceph osd pool create cephfs_data # ceph osd pool create cephfs_metada ...