洛谷 P3246 - [HNOI2016]序列(单调栈+前缀和)
这道题为什么我就没想出来呢/kk
对于每组询问 \([l,r]\),我们首先求出区间 \([l,r]\) 中最小值的位置 \(x\),这个可以用 ST 表实现 \(\mathcal O(n\log n)-\mathcal O(1)\) 维护,那么显然 \(\forall l'\in[l,x],r'\in[x,r],\min\limits_{t\in[l',r']}a_t=a_x\),产生的贡献为 \((r-x+1)(x-l+1)a_x\),于是我们只用计算 \([x+1,r],[l,x-1]\) 两个区间的贡献即可。
这个东西怎么计算呢?考虑枚举区间的右端点 \(R\),我们要计算 \([x+1,R],[x+2,R],\cdots,[R,R]\) 这 \(R-x\) 个区间的最小值之和,我们记 \(pre_x\) 为最大的满足 \(y<x,a_y\le a_x\) 的 \(y\)——\(pre_x\) 显然可以用单调栈在线性时间内求出。再记序列 \(p_1,p_2,\cdots,p_k\) 满足 \(p_0=0,p_k=R,\forall i\in[1,k],p_{i-1}=pre_{p_i}\) 的序列(说白了就是单调栈求完 \(pre_R\) 之后,栈底到栈顶位置上元素的下标依次形成的序列),那么显然 \(\forall i\in[1,k],l\in(p_{i-1},p_i]\) 都有 \(\min\limits_{t=l}^xa_t=a_{p_i}\),也就是说 \(a_{p_i}\) 位置会成为 \(p_i-p_{i-1}\) 个位置的最小值。如果我们记 \(f_R\) 为 \([1,R],[2,R],\cdots,[R,R]\) 的最小值之和,那么根据之前的推论有递推式 \(f_R=f_{pre_R}+(R-pre_R)a_R\),可线性求出。
这里还有一个问题,那就是我们要计算 \([x+1,R],[x+2,R],\cdots,[R,R]\) 的贡献 instead of \([1,R],[2,R],\cdots,[R,R]\),也就是说我们要减去 \([1,R],[2,R],\cdots,[x,R]\) 的贡献。这东西又怎么求呢?很明显 \(p\) 序列有一个性质就是必定 \(\exist id\in[1,k]\) 满足 \(p_{id}=x\),正确性显然,并且容易注意到 \(\forall l\in[1,x],\min\limits_{t=l}^Ra_t=\min\limits_{t=l}^xa_t\),也就是说 \([1,R],[2,R],\cdots,[x,R]\) 的贡献其实就是 \([1,x],[2,x],\cdots,[x,x]\),因此只需拿 \(f_R-f_x\) 就可以得到 \([x+1,R],[x+2,R],\cdots,[R,R]\) 的贡献。
故最终 \([x+1,r]\) 的贡献之和就是 \(\sum\limits_{R=x+1}^rf_R-f_x\),这个显然前缀和随便算一下就行了。求 \([l,x-1]\) 的贡献也同理。
时间复杂度 \(n\log n\),瓶颈在于 RMQ。
const int MAXN=1e5;
const int LOG_N=18;
const int INF=0x3f3f3f3f;
int n,qu,a[MAXN+5],pre[MAXN+5],nxt[MAXN+5];
ll fl[MAXN+5],fr[MAXN+5],gl[MAXN+5],gr[MAXN+5];
pii st[MAXN+5][LOG_N+2];
pii query(int l,int r){
int k=31-__builtin_clz(r-l+1);
return min(st[l][k],st[r-(1<<k)+1][k]);
}
int main(){
scanf("%d%d",&n,&qu);a[0]=a[n+1]=-INF;
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
stack<int> stk;stk.push(0);
for(int i=1;i<=n;i++){
while(!stk.empty()&&a[stk.top()]>=a[i]) stk.pop();
pre[i]=stk.top();stk.push(i);
} while(!stk.empty()) stk.pop();
stk.push(n+1);
for(int i=n;i;i--){
while(!stk.empty()&&a[stk.top()]>=a[i]) stk.pop();
nxt[i]=stk.top();stk.push(i);
}
// for(int i=1;i<=n;i++) printf("%d %d\n",pre[i],nxt[i]);
for(int i=1;i<=n;i++) fl[i]=fl[pre[i]]+1ll*a[i]*(i-pre[i]),gl[i]=gl[i-1]+fl[i];
for(int i=n;i;i--) fr[i]=fr[nxt[i]]+1ll*a[i]*(nxt[i]-i),gr[i]=gr[i+1]+fr[i];
for(int i=1;i<=n;i++) st[i][0]=mp(a[i],i);
for(int i=1;i<=LOG_N;i++) for(int j=1;j+(1<<i)-1<=n;j++)
st[j][i]=min(st[j][i-1],st[j+(1<<i-1)][i-1]);
while(qu--){
int l,r;scanf("%d%d",&l,&r);int p=query(l,r).se;
printf("%lld\n",1ll*a[p]*(p-l+1)*(r-p+1)+gr[l]-gr[p]-1ll*fr[p]*(p-l)+gl[r]-gl[p]-1ll*fl[p]*(r-p));
}
return 0;
}
洛谷 P3246 - [HNOI2016]序列(单调栈+前缀和)的更多相关文章
- 洛谷P3246 [HNOI2016]序列 [莫队]
传送门 思路 看到可离线.无修改.区间询问,相信一定可以想到莫队. 然而,莫队怎么转移是个大问题. 考虑\([l,r]\rightarrow[l,r+1]\)时答案会怎样变化?(左端点变化时同理) \ ...
- 洛谷P3246 [HNOI2016]序列(离线 差分 树状数组)
题意 题目链接 Sol 好像搞出了一个和题解不一样的做法(然而我考场上没写出来还是爆零0) 一个很显然的思路是考虑每个最小值的贡献. 预处理出每个数左边第一个比他小的数,右边第一个比他大的数. 那么\ ...
- 洛谷P3246 [HNOI2016]序列
传送门 题解 //minamoto #include<iostream> #include<cstdio> #define ll long long using namespa ...
- 洛谷P4198 楼房重建 单调栈+线段树
正解:单调栈+线段树 解题报告: 传送门! 首先考虑不修改的话就是个单调栈板子题昂,这个就是 然后这题的话,,,我怎么记得之前考试好像有次考到了类似的题目昂,,,?反正我总觉着这方法似曾相识的样子,, ...
- 洛谷P4147 玉蟾宫 单调栈/悬线法
正解:单调栈/悬线法 解题报告: ummm这题我当初做的时候一点思路也没有只会暴力出奇迹:D(啊听说暴力好像能水过去呢,,, 然后当初是看的题解,然后学了下悬线法 然后就忘了:D 然后我现在看发现看不 ...
- 【bzoj4540】[Hnoi2016]序列 单调栈+离线+扫描线+树状数组区间修改区间查询
题目描述 给出一个序列,多次询问一个区间的所有子区间最小值之和. 输入 输入文件的第一行包含两个整数n和q,分别代表序列长度和询问数.接下来一行,包含n个整数,以空格隔开,第i个整数为ai,即序列第i ...
- 洛谷 P4697 Balloons [CEOI2011] 单调栈/dp (待补充qwq)
正解:单调栈/dp 解题报告: 先放个传送门qwq 话说这题是放在了dp的题单里呢?但是听说好像用单调栈就可以做掉所以我就落实下单调栈的解法好了qwq (umm主要如果dp做好像是要斜率优化凸壳维护双 ...
- 洛谷P3400 仓鼠窝(单调栈)
P3400 仓鼠窝 题目描述 萌萌哒的Created equal是一只小仓鼠,小仓鼠自然有仓鼠窝啦. 仓鼠窝是一个由n*m个格子组成的行数为n.列数为m的矩阵.小仓鼠现在想要知道,这个矩阵中有多少个子 ...
- 洛谷 P1198 [JSOI2008]最大数——单调栈/线段树
先上一波题目 https://www.luogu.org/problem/P1198 题目要求维护后缀最大值 以及在数列的最后面添加一个数 这道题呢我们有两种做法 1.单调栈 因为只需要维护后缀最大值 ...
随机推荐
- 【UE4】GAMES101 图形学作业0:矩阵初识
作业描述 给定一个点P=(2,1), 将该点绕原点先逆时针旋转45◦,再平移(1,2), 计算出变换后点的坐标(要求用齐次坐标进行计算). UE4 知识点 主要矩阵 FMatrix FBasisVec ...
- [Beta]the Agiles Scrum Meeting 7
会议时间:2020.5.21 20:00 1.每个人的工作 今天已完成的工作 成员 已完成的工作 issue yjy 暂无 tq 新增功能:添加.选择.展示多个评测机,对新增功能进行测试 评测部分增加 ...
- rabbitmq生产者消息确认
在使用 RabbitMQ 的时候,有时候当我们生产者发送一条消息到 RabbitMQ 服务器后,我们 生产者想知道消息是否到达了 RabbitMQ 服务器上.这个时候我们应该如何处理? 针对上述问题, ...
- 疯狂Java基础Day2
巩固Java流程控制的学习... 一.用户交互Scanner 通过Scanner类获取用户的输入 import java.util.Scanner; public class Demo1 { publ ...
- Spring Security 的注册登录流程
Spring Security 的注册登录流程 数据库字段设计 主要数据库字段要有: 用户的 ID 用户名称 联系电话 登录密码(非明文) UserDTO对象 需要一个数据传输对象来将所有注册信息发送 ...
- Ubuntu Python2 和 Python3 共存 切换
例如 你写了代码 创建一个文件 在终端 vim test.py 然后写入代码 print "hello world" 接着运行代码 python test.py 会输出 hello ...
- Windows7下面手把手教你安装Django - Hongten
我所使用的操作系统是Windows7,内存是2G 在搜索了一些资料发现,对于Django的安装,详细的真的很少,都说的很简化,然而,这篇blog可以手把手教你成功安装Django 对于Django的详 ...
- 微信小程序API接口封装
@ 目录 一,让我们看一下项目目录 二,让我们熟悉一下这三个文件目的(文件名你看着办) 三,页面js中如何使用 今天的API的封装,我们拿WX小程序开发中,对它的API (wx.request)对这个 ...
- element-UI 中的upload组件如何添加token?
<el-upload :show-file-list="false" :on-error="errmsg" :headers="headers& ...
- 五分钟,让你明白MySQL是怎么选择索引《死磕MySQL系列 六》
系列文章 二.一生挚友redo log.binlog<死磕MySQL系列 二> 三.MySQL强人"锁"难<死磕MySQL系列 三> 四.S 锁与 X 锁的 ...