【LG3246】[HNOI2016]序列

题面

洛谷

题解

60pts

对于每个位置\(i\),单调栈维护它往左第一个小于等于它的位置\(lp_i\)以及往右第一个小于它的位置\(rp_i\)。

那么在左端点在\((lp_i,i]\),右端点在\([i,rp_i)\)的所有区间中,

区间的贡献均为\(a_i\)(之所以取等情况不一样是防止算重或算漏)。

那么对于一个询问\(L,R\),有

\[Ans=\sum_{i=L}^R (i-max(lp_i+1,L)+1)\cdot (min(rp_i-1,R)-i+1)
\]

100pts

考虑莫队,那么我们的难点主要就是怎么从区间\([L,R]\)转移到区间\([L,R+1]\)。

用ST表查一下\([L,R+1]\)的最小值的位置\(p\),则左端点在\([L,p]\)的区间贡献均为\(a[p]\)。

现在考虑左端点在\([p+1,R+1]\)的贡献,记一个类似于前缀和的东西\(f_i=f_{lp_i}+(i-lp_i)*a[i]\),

则可以算出区间\([p+1,R+1]\)的贡献为\(f_{R+1}-f_p\),因为\(f_i\)相当于求\(i\)的\(lp\),它\(lp\)的\(lp\)...

到\(i\)的贡献,而\(p\)必为某一个转移端点,所以成立。

向\([L-1,R]\)转移同样维护一个\(g_i=g_{rp_i}+(rp_i-i)*a[i]\)。

减法直接减去一个位置对区间的贡献即可。

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
inline int gi() {
register int data = 0, w = 1;
register char ch = 0;
while (!isdigit(ch) && ch != '-') ch = getchar();
if (ch == '-') w = -1, ch = getchar();
while (isdigit(ch)) data = 10 * data + ch - '0', ch = getchar();
return w * data;
}
typedef long long ll;
const int MAX_N = 1e5 + 5;
const int LEN = 320;
int N, Q, a[MAX_N], bel[MAX_N];
struct Query { int l, r, id; } q[MAX_N], tmp[MAX_N];
bool operator < (const Query &lhs, const Query &rhs) {
if (bel[lhs.l] == bel[rhs.l]) return (bel[lhs.l] & 1) ? lhs.r < rhs.r : lhs.r > rhs.r;
else return bel[lhs.l] < bel[rhs.l];
}
int stk[MAX_N], top, lp[MAX_N], rp[MAX_N];
int st[18][MAX_N], bin[18], lg[MAX_N];
int query(int l, int r) {
int k = lg[r - l + 1];
if (a[st[k][l]] < a[st[k][r - bin[k] + 1]]) return st[k][l];
else return st[k][r - bin[k] + 1];
}
ll L[MAX_N], R[MAX_N], ans[MAX_N], Ans;
ll Ladd(int l, int r) {
int p = query(l - 1, r);
return 1ll * a[p] * (r - p + 1) + R[l - 1] - R[p];
}
ll Radd(int l, int r) {
int p = query(l, r + 1);
return 1ll * a[p] * (p - l + 1) + L[r + 1] - L[p];
} int main () {
#ifndef ONLINE_JUDGE
freopen("cpp.in", "r", stdin);
freopen("cpp.out", "w", stdout);
#endif
N = gi(), Q = gi();
for (int i = 1; i <= N; i++) a[i] = gi();
for (int i = 1; i <= N; i++) bel[i] = (i - 1) / LEN + 1;
bin[0] = 1; for (int i = 1; i <= 17; i++) bin[i] = bin[i - 1] << 1;
for (int i = 2; i <= N; i++) lg[i] = lg[i >> 1] + 1;
for (int i = 1; i <= N; i++) st[0][i] = i;
for (int i = 1; bin[i] <= N; i++)
for (int j = 1; j + bin[i] - 1 <= N; j++)
if (a[st[i - 1][j]] < a[st[i - 1][j + bin[i - 1]]]) st[i][j] = st[i - 1][j];
else st[i][j] = st[i - 1][j + bin[i - 1]];
for (int i = 1; i <= Q; i++) {
int l = gi(), r = gi();
q[i] = (Query){l, r, i};
}
sort(&q[1], &q[Q + 1]);
stk[0] = 0;
for (int i = 1; i <= N; i++) {
while (a[stk[top]] >= a[i] && top) --top;
lp[i] = stk[top], stk[++top] = i;
}
top = 0, stk[0] = N + 1;
for (int i = N; i >= 1; i--) {
while (a[stk[top]] > a[i] && top) --top;
rp[i] = stk[top], stk[++top] = i;
}
for (int i = 1; i <= N; i++) L[i] = L[lp[i]] + 1ll * (i - lp[i]) * a[i];
for (int i = N; i >= 1; i--) R[i] = R[rp[i]] + 1ll * (rp[i] - i) * a[i];
int ql = 1, qr = 0;
for (int i = 1; i <= Q; i++) {
while (qr < q[i].r) ++qr, Ans += Radd(ql, qr - 1);
while (ql < q[i].l) Ans -= Ladd(ql + 1, qr), ++ql;
while (ql > q[i].l) --ql, Ans += Ladd(ql + 1, qr);
while (qr > q[i].r) Ans -= Radd(ql, qr - 1), --qr;
ans[q[i].id] = Ans;
}
for (int i = 1; i <= Q; i++) printf("%lld\n", ans[i]);
return 0;
}

【LG3246】[HNOI2016]序列的更多相关文章

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

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

  2. 4540: [Hnoi2016]序列

    4540: [Hnoi2016]序列 https://www.lydsy.com/JudgeOnline/problem.php?id=4540 分析: 莫队+RMQ+单调栈. 考虑加入一个点后,区间 ...

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

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

  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. 【BZOJ4540】[Hnoi2016]序列 莫队算法+单调栈

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

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

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

  7. [HNOI2016]序列 CDQ+DP

    [HNOI2016]序列 CDQ 链接 loj 思路 一个点最小变为l,最大变为r,不变的时候为v 那么j能在i前面就要满足. \(j<i\) \(r[j]<=v[i]\) \(v[j]& ...

  8. 题解-[HNOI2016]序列

    题解-[HNOI2016]序列 [HNOI2016]序列 给定 \(n\) 和 \(m\) 以及序列 \(a\{n\}\).有 \(m\) 次询问,每次给定区间 \([l,r]\in[1,n]\),求 ...

  9. P6604 [HNOI2016]序列 加强版

    *I. P6604 [HNOI2016]序列 加强版 摘自学习笔记 简单树论 笛卡尔树部分例题 I. 和 P6503 比较类似.我们设 \(f_i\) 表示全局以 \(i\) 结尾的子区间的最小值之和 ...

随机推荐

  1. 《鸟哥的Linux私房菜》Chapter11 20180726~20180806

    目录 1.认识Bash这个shell 1.1.硬件.核心与shell 1.2.系统的合法shell和/etc/shells功能 1.3.Bash shell的功能 1.3.1.命令修编功能 1.3.2 ...

  2. python 基础-----数字,字符串,if while 循环 数据类型的转换简单介绍

    一.第一个python小程序 首先我们要知道python创立的初衷是:Python崇尚优美.清晰.简单. 所以python比起其他的语言需要的工作量少了一半都不止,比如和现在一直霸占语言排行榜  榜首 ...

  3. 制作 OS X El Capitan 启动盘

    制作 OS X El Capitan 启动盘 1. 下载系统盘的dmg格式 2. 直到出现了 3. 在命令行中找到 Install OS X El Capitan.app 4. 格式化你的U盘(U盘名 ...

  4. CentOS针对磁盘IO[jdb2进程]的优化

    CentOS的jdb2进程总是沾满io,查了一些资料后才知道,这个问题源自系统bug,在此记录一下解决办法: 将高IO的磁盘,用以下参数remount即可 mount -t ext4 -o remou ...

  5. 鸟哥私房菜vim常用命令

    第一部份:一般模式可用的按钮说明,光标移动.复制贴上.搜寻取代等 移动光标的方法 h 或 向左箭头键(←) 光标向左移动一个字符 j 或 向下箭头键(↓) 光标向下移动一个字符 k 或 向上箭头键(↑ ...

  6. JS DateTime 格式化

    首先看我们在浏览器接收到的DateTime格式的数据: 如果没有在传输的时候把DateTime转成字符串的话,我们只需要在JS中加一段代码即可转换,代码如下: function ChangeDateF ...

  7. foreach 计数

    foreach(var item in list.Select((x, i) => new { x, i })){    User user = item.x;    int Idx = ite ...

  8. Python的多线程理解,转自虫师https://www.cnblogs.com/fnng/p/3670789.html

    多线程和多进程是什么自行google补脑 对于python 多线程的理解,我花了很长时间,搜索的大部份文章都不够通俗易懂.所以,这里力图用简单的例子,让你对多线程有个初步的认识. 单线程 在好些年前的 ...

  9. JDK源码学习LinkedList

    LinkedList是List接口的子类,它底层数据结构是双向循环链表.LinkedList还实现了Deque接口(double-end-queue双端队列,线性collection,支持在两端插入和 ...

  10. 洛谷 P1251 餐巾计划问题(线性规划网络优化)【费用流】

    (题外话:心塞...大部分时间都在debug,拆点忘记加N,总边数算错,数据类型标错,字母写错......) 题目链接:https://www.luogu.org/problemnew/show/P1 ...