单调栈(向右扩展)
Posted nonames
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了单调栈(向右扩展)相关的知识,希望对你有一定的参考价值。
转自:https://blog.csdn.net/qq1169091731/article/details/52006440?utm_source=app
1、定义
单调栈是一种特殊的栈,其栈内的元素都保持一个单调性(单调递增或者递减)
2、作用
利用单调栈,可以找到从左(或者右)遍历第一个比它小(或者大)的元素的位置。
也可以说是 求某组数以其中某一个数字为最小值的最大延伸区间
比如 {2 3 2 5 1 4},以第一个2为最小值可以延伸的区间为{2, 3, 2, 5}
3、算法过程
假设有一个单调递增的栈 S和一组数列: a = { 5 3 7 4}
用数组L[i]
表示 第i个数向左遍历的第一个比它小的元素的位置
一个元素向左遍历的第一个比它小的数的位置就是将它插入单调栈时栈顶元素的值,
若栈为空,则说明不存在这么一个数。然后将此元素的下标存入栈,就能类似迭代般地求解后面的元素
4、模板
stack<int> s; for(int i = 1; i <= n; ++i) { while(s.size() && a[s.top()] >= a[i]) s.pop(); if(s.empty()) l[i] = 0; else l[i] = s.top(); s.push(i);
5、应用
1.给定一组数,针对每个数,寻找它和它左边第一个比它小的数之间有多少个数。
2.给定一序列,寻找某一子序列,使得子序列中的最小值乘以子序列的长度最大。
3.给定一序列,寻找某一子序列,使得子序列中的最小值乘以子序列所有元素和最大。
例题:http://poj.org/problem?id=3250
题意:有n头牛站一排且向右看,给出每条牛的高度,问每头牛可看到其他牛的头的总和和多少。
解法:就是求每一条牛的右边第一条比该条牛大的距离之和;
构造单调递减栈:满足弹栈时:栈顶牛的右边第一头比栈顶牛高的牛为即将入栈的牛;
//#include <bits/stdc++.h> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <iostream> #include <string> #include <stdio.h> #include <queue> #include <stack> #include <map> #include <set> #include <string.h> #include <vector> #define ME(x , y) memset(x , y , sizeof(x)) #define SC scanf #define rep(i ,j , n) for(int i = j ; i < n ; i ++) #define red(i , n , j) for(int i = n-1 ; i >= j ; i--) #define INF 0x3f3f3f3f #define mod 998244353 #define PI acos(-1) #define lson k<<1,l,mid #define rson k<<1|1,mid+1,r using namespace std; typedef long long ll ; ll a[80009]; ll s[80009], top;//单调递减栈 int main(){ int n;cin>>n; rep(i , 1 , n+1){ scanf("%lld" , &a[i]); } a[n+1] = INF;//将栈压空 ll ans = 0 ; rep(i , 1 , n+2){ while(top && a[s[top-1]] <= a[i]){//求出每一头牛的右边比该头牛高的第一条牛 ans += i - s[top-1] -1 ;//此时i牛为栈顶牛的右边第一头比栈顶牛高的牛 top--; } s[top++] = i ; } cout << ans << endl; }
以上是关于单调栈(向右扩展)的主要内容,如果未能解决你的问题,请参考以下文章
Largest Rectangle in a Hitogram-单调栈の入门好题