【单调栈】
【单调栈】
定义
模版代码
#include<bits/stdc++.h>
using namespace std;
const int N=100010;
int n;
int tt;
long long stk[N];
long long x;
int main(){
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%lld",&x);
//栈首先要不为空
while(tt && stk[tt]>=x) tt--;
if(tt) printf("%lld ",stk[tt]);
else printf("-1 ");
stk[++tt]=x;
}
return 0;
}
模版题
https://www.luogu.com.cn/problem/P2866
/*【思路】
比当前加进来的矮的->弹出
剩下的就是【当前在栈里】能看到这个数的(求一头牛能被多少头牛看见)
->再加进栈里
*/
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef long long ll;
const int N=80010;
int n;
int a[N],stk[N];
int cnt=-1;
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
ll ans=0;
for(int i=1;i<=n;i++){
//注意这里是严格递减->保持单调性!
while(cnt>=0 && stk[cnt]<=a[i]) cnt--;
ans+=cnt+1;
stk[++cnt]=a[i];
}
cout<<ans;
return 0;
}
应用
求最大子矩阵面积
City Game
https://fjnuacm.top/d/minor/p/226?tid=66bcba9e7d902b243e152ae7
举例
代码
/*【单调栈求最大子矩形面积(变式)】
对于每一行 看做一个矩形
*/
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
const int N=1010;
int n,m;
string a;
int f[N][N],h[N][N],s[N],w[N];//h高度 s高度栈 w宽度栈
int p=0,ans=-1;
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>a;
if(a[0]=='R') f[i][j]=0;
else if(a[0]=='F') f[i][j]=1;
}
}
//预处理
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(f[i][j]) h[i][j]=h[i-1][j]+1;//高度累加
}
}
//单调栈:对于每一行都按照最大子矩形面积做一遍
for(int i=1;i<=n;i++){//每一行
memset(s,0,sizeof s);
memset(w,0,sizeof w);
for(int j=1;j<=m+1;j++){//列遍历:最后要0收尾
if(s[p]<=h[i][j]){
s[++p]=h[i][j];
w[p]=1;
}
else{
//在出栈时计算以当前出栈元素为高度的矩形的最大宽度
int wid=0;
while(s[p]>h[i][j]){
wid+=w[p];//累加:给后面的用(后面的<=都可以用前面长的)
ans=max(ans,wid*s[p]);
p--;
}
s[++p]=h[i][j];
w[p]=wid+1;
}
}
}
printf("%d",ans*3);
return 0;
}