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. SpringCloud之Ribbon负载均衡及Feign消费者调用服务

    目的: 微服务调用Ribbon Ribbon负载均衡 Feign简介及应用 微服务调用Ribbon Ribbon简介 1. 负载均衡框架,支持可插拔式的负载均衡规则 2. 支持多种协议,如HTTP.U ...

  2. Relative Sort Array

    Relative Sort Array Given two arrays arr1 and arr2, the elements of arr2 are distinct, and all eleme ...

  3. 关于梯度下降之前需要进行feature scale的记录

    先上吴恩达老师的课件图 1.对于梯度下降而言,学习率很大程度上影响了模型收敛的速度.对于不同规模的特征,如果采用相同的学习率,那么如果学习率适应于scale大的数据,scale较小的数据由于学习率过大 ...

  4. node-red 使用 创建第一个流程

    前言 这只是一个简单的示例,具体详细文档去官网查看 官网指南:https://nodered.org/docs/user-guide/ 打开浏览器,进入编辑器页面:http://localhost:1 ...

  5. springboot 2.1.3.RELEASE添加filter,servlet源码学习

    Servlet规范中,通过ServeltContext来注册Filter.Servlet,这里分析Filter,Servlet是相同逻辑 springboot2.0中,我们通过 FilterRegis ...

  6. 二叉排序树详解——PHP代码实现

    二叉排序树(Binary Sort Tree),又称二叉查找树(Binary Search Tree),亦称二叉搜索树. 一.定义 二叉排序树或者是一棵空树,或者是具有下列性质的二叉树: 若左子树不空 ...

  7. 【开发工具】- Xshell工具的下载和安装

    下载地址:https://www.netsarang.com/zh/free-for-home-school/ Xshell 是一个强大的安全终端模拟软件,它支持SSH1, SSH2, 以及Micro ...

  8. 【转载】 C#使用string.IsNullOrWhiteSpace方法判断字符串是否为非空字符

    在C#编程过程中,很多时候需要判断传入过来的字符串是否为Null或者空字符或者空白字符,此时就可以使用到string.IsNullOrWhiteSpace方法来判断,如果字符串为null或者空字符Em ...

  9. GitHub上传文件问题总结

    问题一:git warning: LF will be replaced by CRLF in 解决办法 在Git Bash中输入git add .时出现上述语句. 解决办法: 输入以下语句: $ g ...

  10. 爬虫之post请求与请求传参

    一.POST请求 class Postspider(scripy.Spider): name = "post" # allowed_domains = ["www.xxx ...