hnoi 2016

标签:题解


莫队

考虑左端点左移以及右端点右移产生的贡献

这样就可以由 \([l, r]\) 转移到另外的 \(4\) 个区间

\(f_{l, r}\) 表示右端点在 \(r\), 左端点在 \([l, r]\) 内的答案,这个可以压掉一维

\(pre_{i}\) 表示 \(i\) 前面第一个比 \(a_{i}\) 小的数的位置

\(bhd_{i}\) 表示 \(i\) 后面第一个比 \(a_{i}\) 小的数的位置

考虑计算贡献 \(S\)

也就是右端点右移产生的贡献

显然新增加贡献的区间的右端点只有 \(r + 1\),

发现,在 \((pre_{r} + 1, r + 1]\) 这段区间是单调递减的

那么所有左端点在 \((pre_{r} + 1, r + 1]\) 产生的贡献为 \(a_{r + 1} * Len, Len\) 表示区间长度

我们现在另 \(r2 = pre_{r}\), 那么所有左端点在 \((pre_{r2} + 1, r2]\) 产生的贡献为 \(a_{r2} * Len\)

一直这样下去的话就会找到一个 \(x\) 使得 \(a_{pre_{x}}\) 为区间 \([l, r + 1]\) 的最小值, 记 \(p = pre_{x}\)

记此时的总和为 \(S_{1}\) 就是之前的区间产生的贡献

并且所有左端点在 \([l, p]\) 产生的贡献为 \(S_{2} = a_{p} \times ({p - l + 1})\)

那么

\[f_{l, r + 1} = a_{r + 1} \times (r + 1 - pre_{r + 1}) + \cdots + a_{x} \times (x - pre_{x}) + f_{l, p}
\]

压掉第一维

\[f_{r + 1} = a_{r + 1} \times (r + 1 - pre_{r + 1}) + \cdots + a_{x} \times (x - pre_{x}) + f_{p}
\]

增量

\[S_{2} = f_{r + 1} - f_{p}
\]

对于 \(f_{i}\) 预处理, \(O(1)\) 查询增量

\[S = S_{1} + S_{2}
\]

对于左端点左移

对称处理 \(f_{}\)

#include <bits/stdc++.h>

const int N = 1e5 + 10;

int A[N], pos[N], size;
int n, m;
struct Node {
int l, r, id;
bool operator < (Node a) const {
if(pos[l] == pos[a.l]) return r < a.r;
return l < a.l;
}
} Ask[N];
int Log[N], Pow[N];
int f[N][30];
int Stack[N], topp, pre[N], bhd[N];
int block; #define LL long long
LL fl[N], fr[N], Answer[N]; inline int Ask_min(int l, int r) {
int t = Log[r - l + 1];
return (A[f[l][t]] < A[f[r - Pow[t] + 1][t]] ? f[l][t] : f[r - Pow[t] + 1][t]);
} inline LL Left(int l, int r) {
int p = Ask_min(l - 1, r);
return 1ll * A[p] * (r - p + 1) + fl[l - 1] - fl[p];
} inline LL Right(int l, int r) {
int p = Ask_min(l, r + 1);
return 1ll * A[p] * (p - l + 1) + fr[r + 1] - fr[p];
} #define Rep(i, a, n) for(int i = a; i <= n; i ++) int main() {
std:: cin >> n >> m;
for(int i = 1; i <= n; i ++) std:: cin >> A[i];
A[0] = A[n + 1] = (1 << 30);
for(int i = 1; i <= m; i ++) {
std:: cin >> Ask[i].l >> Ask[i].r;
Ask[i].id = i;
}
block = sqrt(n);
for(int i = 1; i <= n; i ++) pos[i] = (i - 1) / block + 1;
for(int i = 1; i <= n; i ++) f[i][0] = i;
std:: sort(Ask + 1, Ask + m + 1);
for(int i = 0; (Pow[i] = (1 << i)) <= n; i ++);
for(int i = 2; i <= n; i ++) Log[i] = Log[i >> 1] + 1;
for(int i = 1; Pow[i] <= n; i ++)
for(int j = 1; j <= n - Pow[i - 1] + 1; j ++)
f[j][i] = (A[f[j][i - 1]] > A[f[j + Pow[i - 1]][i - 1]] ? f[j + Pow[i - 1]][i - 1] : f[j][i - 1]);
for(int i = 1; i <= n; i ++) {
while(topp && A[Stack[topp]] > A[i]) {
bhd[Stack[topp]] = i;
topp --;
}
pre[i] = Stack[topp];
Stack[++ topp] = i;
}
while(topp) bhd[Stack[topp --]] = n + 1;
for(int i = 1; i <= n; i ++) fr[i] = fr[pre[i]] + 1ll * A[i] * (i - pre[i]);
for(int i = n; i >= 1; i --) fl[i] = fl[bhd[i]] + 1ll * A[i] * (bhd[i] - i);
int l = 1, r = 0;
LL Ans = 0;
for(int i = 1; i <= m; i ++) {
int x = Ask[i].l, y = Ask[i].r;
while(l > x) Ans += Left(l, r), l --;
while(r < y) Ans += Right(l, r), r ++;
while(l < x) Ans -= Left(l + 1, r), l ++;
while(r > y) Ans -= Right(l, r - 1), r --;
Answer[Ask[i].id] = Ans;
}
for(int i = 1; i <= m; i ++) std:: cout << Answer[i] << "\n";
return 0;
}

luogu 3246 莫队+RMQ+单调栈的更多相关文章

  1. BZOJ4540 Hnoi2016 序列 【莫队+RMQ+单调栈预处理】*

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

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

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

  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. [HNOI2016]序列(莫队,RMQ)

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

  5. 【bzoj3879】SvT 后缀数组+倍增RMQ+单调栈

    题目描述 (我并不想告诉你题目名字是什么鬼) 有一个长度为n的仅包含小写字母的字符串S,下标范围为[1,n]. 现在有若干组询问,对于每一个询问,我们给出若干个后缀(以其在S中出现的起始位置来表示), ...

  6. luogu 1169 棋盘制作(单调栈/悬线)

    luogu 1169 棋盘制作(单调栈/悬线) 国际象棋是世界上最古老的博弈游戏之一,和中国的围棋.象棋以及日本的将棋同享盛名.据说国际象棋起源于易经的思想,棋盘是一个8*8大小的黑白相间的方阵,对应 ...

  7. bzoj4540 序列 (单调栈+莫队+rmq)

    首先,如果我知道[l,r],要转移到[l,r+1]的时候,就是加上以r+1为右端点,[l,r+1]为左端点的区间的最小值,其他情况和这个类似 考虑这玩意怎么求 右端点固定的话,我左端点越往左走,这个最 ...

  8. Gym - 102028H Can You Solve the Harder Problem? (后缀数组+RMQ+单调栈)

    题意:求一个序列中本质不同的连续子序列的最大值之和. 由于要求“本质不同”,所以后缀数组就派上用场了,可以从小到大枚举每个后缀,对于每个sa[i],从sa[i]+ht[i]开始枚举(ht[0]=0), ...

  9. luogu P4887 莫队二次离线

    珂朵莉给了你一个序列$a$,每次查询给一个区间$[l,r]$ 查询$l≤i<j≤r$,且$ai⊕aj$的二进制表示下有$k$个$1$的二元组$(i,j)$的个数.$⊕$是指按位异或. 直接暴力莫 ...

随机推荐

  1. tkinter学习笔记_01

    知识点目录: 1. 文本框 Label var = tk.StringVar() # 文本框 bg 背景颜色 fonnt 字体设置 width 长 height 高 l = tk.Label(root ...

  2. nginx配置http静态站点服务器

    1.  系统环境Windows 10 2.  设置静态站点目录,注意不要出现中文(这里踩了很多坑,可以查看错误日志error.log, “No mapping for the Unicode char ...

  3. 在Unity中创建VR游戏

    添加VR插件为了为您选择的平台创建VR游戏,我们需要下载几个插件.出于本教程的目的,我将向您展示如何上传到Android平台.要上传到iOS,您需要下载 Xcode. 现在让我们下载Unity的Goo ...

  4. 网络编程-tcp三次握手和四次挥手

    TCP三次握手和四次挥手过程 1.三次握手 (1)三次握手的详述 首先Client端发送连接请求报文,Server段接受连接后回复ACK报文,并为这次连接分配资源.Client端接收到ACK报文后也向 ...

  5. mtd交叉编译mkfs命令

    下载 mtd:ftp://ftp.infradead.org/pub/mtd-utils/ zlib:http://www.zlib.net/ lzo:http://bouchez.info/lzo. ...

  6. vs code 调试设置

    首先vs code 安装插件:Debugger for Chrome vscode 设置:点击调试按钮,然后调试面板界面再点击设置按钮,添加一个配置,选择环境为:chrome编辑器自动生成一个laun ...

  7. Oracle内存管理方式由amm切换为asmm

    (一)ASMM和AMM 在Oracle 10g时,Orale推出ASMM(Automatic Shared Memory Managed),实现了SGA和PGA各自内部的自调节.在Oracle 11g ...

  8. 六、MySQL系列之数据备份(六)

    本篇主要介绍用户授权.以及数据备份等知识: 一.用户授权 首先我们需要知道的是: 所有的用户及权限信息都存储在mysql数据库下的user表中,故我们可以通过查看user表的记录来查看用户权限信息,当 ...

  9. Linux之redis-cluster

    一,为什么要用redis-cluster 1.并发问题 redis官方生成可以达到 10万/每秒,每秒执行10万条命令假如业务需要每秒100万的命令执行呢? 2.数据量太大 一台服务器内存正常是16~ ...

  10. Nginx配置文件示例

    Nginx的配置文件示例:(仅供参考) 强烈建议先将默认的配置文件备份再进行操作! 请根据自己项目的实际路径来配置相关路径! uwsgi配置文件请参考:uwsgi配置文件示例 # For more i ...