题目

  给定长度为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. 操作系统(5)_内存管理_李善平ppt

    i386先通过段是管理,在通过页是管理

  2. Java算法面试题:编写一个程序,将e:\neck目录下的所有.java文件复制到e:\jpg目录下,并将原来文件的扩展名从.java改为.jpg

    package com.swift; import java.io.File; import java.io.FileFilter; import java.io.FileInputStream; i ...

  3. c++异常处理--创建自己的异常处理类

    复习了一下c++中的异常处理! 继承exception类 class myException : public std::exception { public: explicit myExceptio ...

  4. SPOJ1043 GSS1(线段树)

    题意 给出$n$个数,每次询问区间$(l, r)$内最大字段和 Sol 在合并子树的时候,答案仅有四种情况 打四个标记维护即可 查询同理,用类似update的方式合并 注意查询的时候不能按照以前的方式 ...

  5. Java泛型和反射

    1. 字节码对象的三种获取方式 以String为例 Class<? extends String> strCls = "".getClass(); Class<S ...

  6. JZOJ 4722. 跳楼机

    Description  DJL为了避免成为一只咸鱼,来找srwudi学习压代码的技巧.Srwudi的家是一幢h层的摩天大楼.由于前来学习的蒟蒻越来越多,srwudi改造了一个跳楼机,使得访客可以更方 ...

  7. JZOJ 2499. 东风谷早苗

    2499. 东风谷早苗 (Standard IO) Time Limits: 1000 ms  Memory Limits: 131072 KB  Detailed Limits   Goto Pro ...

  8. Java集合框架汇总

    HashMap是一个最常用的Map,它根据键的HashCode值存储数据,根据键可以直接获取它的值,具有很快的访问速度,遍历时,取得数据的顺序是完全随机的.HashMap最多只允许一条记录的键为NUL ...

  9. 3 View - 状态保持 session

    1.状态保持 http协议是无状态的:每次请求都是一次新的请求,不会记得之前通信的状态 客户端与服务器端的一次通信,就是一次会话 实现状态保持的方式:在客户端或服务器端存储与会话有关的数据 存储方式包 ...

  10. HDU 1847 Good Luck in CET-4 Everybody!(SG函数)

    Good Luck in CET-4 Everybody! Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K ...