以cf622(Div.2)的C2题为例讲解一下吧:
**题意:**就是找单峰值。建设大楼,要求每栋楼有限高,而且不允许存在一栋楼两边都有比他更高的楼,要求建成的楼总高度最大。
这里我们引入一个单调栈的东西:花了2小时才算勉强搞明白了(感谢wucstdio大佬)
这里运用单调栈来做的话,时间复杂度只有O(n),难点在于这个单调栈该如何去写。下面上ac的代码,里面单调栈的部分运用了2次,分别是求上升的单调栈和下降的单调栈。在这里我对上升的单调栈进行了注释,下降的单调栈其本质类似,所以不加赘述。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int n,a[500005];
int st[500005],num[500005],top;
ll s[500005],pre[500005],suf[500005];
ll ans,pos;
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=1;i<=n;i++)
{
ll now=1;
while(top&&a[i]<=st[top]) //如果top存在并且当前访问值a[i]小于等于前一个top值
{
now+=num[top]; //需要更改的长度值+=top所占据的长度
top--; //把top的位置向前移动
}
st[++top]=a[i]; //更改top的值为当前的a[i]
num[top]=now; //更改当前top所占据的长度
s[top]=s[top-1]+now*a[i]; //当前top的前缀和=前一个top的前缀和+当前的top(a[i])*其所霸占的长度
pre[i]=s[top];
}
top=0;
for(int i=n;i>=1;i--)
{
ll now=1;
while(top&&a[i]<=st[top])
{
now+=num[top];
top--;
}
st[++top]=a[i];
num[top]=now;
s[top]=s[top-1]+now*a[i];
suf[i]=s[top];
}
for(int i=1;i<=n;i++)
{
if(ans<pre[i]+suf[i]-a[i])
{
ans=pre[i]+suf[i]-a[i];
pos=i;
}
}
for(int i=pos-1;i>=1;i--)a[i]=min(a[i],a[i+1]);
for(int i=pos+1;i<=n;i++)a[i]=min(a[i],a[i-1]);
for(int i=1;i<=n;i++)printf("%d ",a[i]);
printf("\n");
return 0;
}