单调栈
可以方便(O(n))地求出一个数,左右第一个比它大/小的数的位置
如何求----
给一个序列 2,3,6,9,4,7,1
我们先求左边第一个比它小的
栈为空,a[S.top()]<a[1] 所以 l[1]=0,S.push(1)
单调栈里存的是编号
接下来a[S.top()]<a[2] 所以l[2]=S.top=1, S.push(1)
同理
但是到4的时候
a[S.top()]>a[5] 所以S.pop()
知道pop到3 此时 l[5]=S.top=1
总结一下有三步
1.把比它大的挤出去
2.栈顶为答案
3.将编号压入栈
我们发现栈始终是单调的
因为比当前数大的数会被挤出去
那右边的怎么求呢, 我们把序列反过来->1,7,4,9,6,3,2
然后按跟左边一样的方法求r[i]
代码
for(int i=1;i<=n;i++){
while(!S.empty()&&a[i]>=a[S.top()]) S.pop();//挤出去
//一定记得+!S.empty
if(S.empty()) l[i]=0;
else l[i]=S.top();
S.push(i);
}
while(S.empty()) S.pop();//记得清零
for(int i=n;i>=1;i--){
while(!S.empty()&&a[i]>=a[S.top()]) S.pop();
if(S.empty()) r[i]=n+1;
else r[i]=S.top();
S.push(i);
}
单调队列
整理归纳单调队列的定义:
1、维护区间最值;
2、去除冗杂状态;
3、保持队列单调(最大值是单调递减序列,最小值是单调递增序列);
4、最优选择在队首。
整理归纳单调队列的使用方法:
1、维护队首;
2、在队尾插入(每插入一个就要从队尾开始往前去除冗杂状态) ;
3、取出需要的最优解(队列头的值即是),借助最优解,得到目前所求的最优解(通常此处插入DP方程)。单调队列的原理:
在处理f[i]时,去除冗杂、多余的状态,使得每个状态在队列中只会出现一次;同时维护一个能瞬间得出最优解的队列,减少重新访问的时间;在取得自己所需的值后,为后续的求解做好准备。
----https://blog.csdn.net/a_bright_ch/article/details/77076228
主要用于dp
对于所有
f[i] = max ( f[j] ) + x (x1 < = j < i)
都可以用单调队列
上面使用方法操作代码
deque<int> q;
1
while(!q.empty()&&q.front()) q.pop_front();
2
while(!q.empty()&&a[q.front()]<a[i]) q.pop_back();
q.push_back(i);
3
f[i]=f[q.front]+x