ios::sync_with_stdio(false);
算法学习笔记(67): 单调栈 - 知乎 (zhihu.com)
模板
1.普通应用
[1,2,3,4,3,2,1]
求左面第一个小于等于a[i](单调递增栈),求右面第一个小于等于a[i](将数组反过来遍历)
for(int i=0;i<n;i++){
while(!top&&a[s[top]]>a[i])top--;
int now=s[top];
last[i]=now;//last为a[i]左面第一个小于等于a[i]的下标
s[++top]=i;
}
二.两元素间所有元素均(不)大/小于这两者问题(让此数和栈顶比较)
for(int i=0;i<n;i++){
int x=read();
int cnt=0;
while(!q.empty()&&q.top().first<=x){
if(q.top().first==x)
cnt=q.top().second;
ans+=q.top().second;
q.pop();
}
if(!q.empty())ans++;
q.emplace(x,cnt+1);
}
对于单调递增栈
1.栈中元素都是单调递增的
2.当栈顶元素出栈时,说明这个新元素是栈顶元素向后查找的第一个比其小的元素
3.当出栈后,新栈顶元素是出栈元素向前查找第一个比其小的元素
http://bailian.openjudge.cn/practice/2559?lang=en_US
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<map>
#include<stack>
using namespace std;
int a[1000005];
int n,m;
int p[100005];
int r[100005];
int l[100005];
int main(){
int w;
while(cin>>n){
if(n==0)break;
memset(l,0,sizeof(l));
memset(r,0,sizeof(r));
for(int i=1;i<=n;i++){
cin>>a[i];
}stack<int>q;
q.push(0);
a[0]=-1;
a[n+1]=-1;//注意,a[n]的前后要有判断
for(int i=1;i<=n+1;i++){
while(a[q.top()]>a[i]){//当前高度大于栈顶高度时
int temp=q.top();//取出栈顶元素备用
q.pop();//出栈
r[temp]=i-temp;//刚刚栈顶元素,右面大于a[temp]的个数,包含a[temp]
}
if(a[i]==a[q.top()]){//定于时
l[i]=l[q.top()]+i-q.top();
}
else{//小于时
l[i]=i-q.top()-1;
}
q.push(i);
}
long long ans=-1;
for(int i=1;i<=n;i++){
ans=max(ans,(long long)a[i]*(l[i]+r[i]));
}
cout<<ans<<endl;
}
}
https://www.luogu.com.cn/problem/P5788
#include<iostream>
#include<stack>
using namespace std;
const int N=3000005;
int l[N],r[N],a[N],ans[N];
#define IFN 1e9+6;
int main(){
int n;
ios::sync_with_stdio(false);
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
stack<int>q;
q.push(0);
a[0]=IFN;
a[n+1]=IFN;
for(int i=1;i<=n;i++){
while(a[i]>a[q.top()]){
int temp=q.top();
q.pop();
ans[temp]=i;
}
q.push(i);
}
for(int i=1;i<=n;i++){
cout<<ans[i]<<' ';
}
}
记录详情 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) (单调栈优化DP)
#include<iostream>
#include<stack>
using namespace std;
const int N=500005;
long long a[N];
long long s[N];
long long dpl[N],dpr[N];
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
int top=0;
for(int i=1;i<=n;i++){
while(top&&a[s[top]]>a[i])top--;
int now=s[top];
dpl[i]=a[i]*(i-now)+dpl[now];
s[++top]=i;
}
while(top)top--;
s[++top]=n+1;
for(int i=n;i>0;i--){
while(top&&a[s[top]]>a[i])top--;
int now=s[top];
dpr[i]=a[i]*(now-i)+dpr[now];
s[++top]=i;
}
long long ans=0;
int p=0;
for(int i=1;i<=n;i++){
if(dpr[i]+dpl[i]-a[i]>ans){
ans=dpr[i]+dpl[i]-a[i];
p=i;
}
}
int cnt=a[p];
for(int i=p;i>0;i--){
if(a[i]>=cnt){
a[i]=cnt;
}
else {
cnt=a[i];
}
}
cnt=a[p];
for(int i=p;i<=n;i++){
if(a[i]>=cnt){
a[i]=cnt;
}
else {
cnt=a[i];
}
}
for(int i=1;i<=n;i++){
cout<<a[i]<<' ';
}
}