一维的单调栈,单调队列:
AcWing 830. 单调栈
#include<iostream>
using namespace std;
const int N=1e5+5;
int n,a[N],l[N];
int stackk[N];
int main(){
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
a[0]=-1;
int ttop=0;
stackk[++ttop]=0;
for(int i=1;i<=n;i++){
while(a[stackk[ttop]]>=a[i]) ttop--;
l[i]=stackk[ttop];
stackk[++ttop]=i;
}
for(int i=1;i<=n;i++) cout<<a[l[i]]<<" ";
return 0;
}
AcWing 154. 滑动窗口
#include<iostream>
using namespace std;
const int N=1e6+5;
int n,k,a[N];
int que[N];
int main(){
int n,k;
cin>>n>>k;
for(int i=1;i<=n;i++) cin>>a[i];
//队头存储min值
int head=0,tail=-1;
for(int i=1;i<=n;i++){
while(head<=tail&&que[tail]>a[i]) tail--;
que[++tail]=a[i];
if(i-k>=1&&que[head]==a[i-k]) head++;
if(i>=k) cout<<que[head]<<" ";
}
cout<<endl;
//队头存储max值
head=0,tail=-1;
for(int i=1;i<=n;i++){
while(head<=tail&&que[tail]<a[i]) tail--;
que[++tail]=a[i];
if(i-k>=1&&que[head]==a[i-k]) head++;
if(i>=k) cout<<que[head]<<" ";
}
return 0;
}
二维的单调栈,单调队列:
AcWing 1413. 矩形牛棚
#include<iostream>
using namespace std;
const int N=3e3+5;
int n,m,p,ans;
int a[N][N];//地图:0表示未破坏,1表示被破坏
int h[N][N];//h[i][j]表示坐标i,j的向上连续且未被破坏的土地
int stackk[N],top,l[N],r[N];
//有了行的基础,遍历列,求当前行往上的最大矩形土地
int work(int h[]){
//放置左右边界
h[0]=h[m+1]=-1;
//找左边界
top=0;//初始化
stackk[++top]=0;//stackk存储的是h数组的下标
for(int i=1;i<=m;i++){
//当栈顶元素>=当前元素时出栈
while(h[stackk[top]]>=h[i]) top--;
l[i]=stackk[top];//存储下标
stackk[++top]=i; //入栈
}
//找右边界
top=0;
stackk[++top]=m+1;
for(int i=m;i;i--){
while(h[stackk[top]]>=h[i]) top--;
r[i]=stackk[top];
stackk[++top]=i;
}
//遍历计算取最值
int res=0;
for(int i=1;i<=m;i++) res=max(res,h[i]*(r[i]-l[i]-1));
return res;
}
int main(){
cin>>n>>m>>p;
//破坏土地
while(p--){
int x,y;
cin>>x>>y;
a[x][y]=1;
}
//从(1,1)-->(n,m)递推h数组
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(a[i][j]==0)
h[i][j]=h[i-1][j]+1;
//遍历行
for(int i=1;i<=n;i++) ans=max(ans,work(h[i]));
cout<<ans<<endl;
return 0;
}
AcWing 4964. 子矩阵(第十四届省赛)
先按列预处理,分别求得当前的最大值最小值,再按行处理分别求出最后的最大值最小值,最后注意答案的取模处理:
#include<iostream>
using namespace std;
const int N=1e3+5;
const int mod=998244353;
int n,m,a,b,A[N][N],MAX[N][N],MIN[N][N],MAXX[N][N],MINN[N][N];
int que[N];
int main(){
cin>>n>>m>>a>>b;
for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) cin>>A[i][j];
for(int j=1;j<=m;j++){
int head=0,tail=-1;
for(int i=1;i<=n;i++){
while(head<=tail&&que[tail]<A[i][j]) tail--;
que[++tail]=A[i][j];
if(i-a>=1&&que[head]==A[i-a][j]) head++;
if(i>=a) MAX[i][j]=que[head];
}
}
for(int j=1;j<=m;j++){
int head=0,tail=-1;
for(int i=1;i<=n;i++){
while(head<=tail&&que[tail]>A[i][j]) tail--;
que[++tail]=A[i][j];
if(i-a>=1&&que[head]==A[i-a][j]) head++;
if(i>=a) MIN[i][j]=que[head];
}
}
for(int i=1;i<=n;i++){
int head=0,tail=-1;
for(int j=1;j<=m;j++){
while(head<=tail&&que[tail]<MAX[i][j]) tail--;
que[++tail]=MAX[i][j];
if(j-b>=1&&que[head]==MAX[i][j-b]) head++;
if(j>=b) MAXX[i][j]=que[head];
}
}
for(int i=1;i<=n;i++){
int head=0,tail=-1;
for(int j=1;j<=m;j++){
while(head<=tail&&que[tail]>MIN[i][j]) tail--;
que[++tail]=MIN[i][j];
if(j-b>=1&&que[head]==MIN[i][j-b]) head++;
if(j>=b) MINN[i][j]=que[head];
}
}
long long ans=0;
for(int i=a;i<=n;i++){
for(int j=b;j<=m;j++){
ans+=((long long)MINN[i][j]*MAXX[i][j])%mod;
ans%=mod;
}
}
cout<<ans<<endl;
return 0;
}