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. quartz2.3.0(七)调度器中断任务执行,手动处理任务中断事件

    job任务类 package org.quartz.examples.example7; import java.util.Date; import org.slf4j.Logger; import ...

  2. Oracle中的dual表简介

    dual是一个虚拟表,用来构成select的语法规则,oracle保证dual里面永远只有一条记录.我们可以用它来做很多事情,如下: 1.查看当前用户,可以在 SQL Plus中执行下面语句 sql代 ...

  3. .NET母版实例2(UI页面)

    8.<div  id="navlist"> <asp:SiteMapDataSource  ID="SiteMapDataSource1"  ...

  4. HTTP API 认证授权术

    原文:https://coolshell.cn/articles/19395.html 我们知道,HTTP是无状态的,所以,当我们需要获得用户是否在登录的状态时,我们需要检查用户的登录状态,一般来说, ...

  5. Step by Step to create orders by consuming SAP Commerce Cloud Restful API

    Recently Jerry is working on an integration project about creating orders in Wechat platform by cons ...

  6. python实战项目

    没有一个完整的项目开发过程,是不会对整个开发流程以及理论知识有牢固的认知的,对于怎样将所学的理论知识应用到实际开发中更是不得而知了! 以上就是我们在学习过程中必须要有项目实战开发经验的原因,其实无论项 ...

  7. Python学习日记(二十五) 接口类、抽象类、多态

    接口类 继承有两种用途:继承基类的方法,并且做出自己的改变或扩展(代码重用)和声明某个子类兼容于某基类,定义一个接口类interface,接口类中定义了一些接口名(就是函数名)且并未实现接口的功能,子 ...

  8. MySQL Lock--gap before rec insert intention waiting

    在事务插入数据过程中,为防止其他事务向索引上该位置插入数据,会在插入之前先申请插入意向范围锁,而如果申请插入意向范围锁被阻塞,则事务处于gap before rec insert intention ...

  9. python(For/while循环语句)

    一.循环语句 1.while循环 当我们在python中需要重复执行一些动作的时候,这时我们就要用到循环 while循环的结构,当条件成立的时候,就会执行里面的代码 while循环不断的运行,直到指定 ...

  10. Linux将用户添加到组的指令

    原文:https://blog.csdn.net/youmatterhsp/article/details/80549683:           https://www.cnblogs.com/cl ...