单调栈:栈里面的元素全部都是单调递增或单调递减的栈
思路:枚举每个元素作为最小元素所能管辖的区间,通过单调栈从1~n扫一遍找到右边界,再从n~1扫一遍找到每个元素所能管辖的区间的左边界,具体的操作就是当前元素小于栈顶元素是,栈顶元素出栈,界定其左(右)边界,重复此操作,直到当前元素大于等于栈顶元素,把当前元素入栈,找完每个元素所管辖的区间之后,我们再用线段树维护一下这个序列的前缀和,对于最小元素为负数的,我们要的是其管辖区间子区间和最小的,只需i~r找最小的前缀和,l-1~i找最大的前缀和,相减就能得到和最小的子区间,需要注意一点,若最大前缀和为负数,则令其等于0,然后对于最小元素为正数的,只要把它所管辖的区间里的数全加起来就行了
代码:
#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define ll long long
const int maxn=5e5+9;
ll a[maxn],sum[maxn];//sum表示前缀和
struct node{
ll val,pos;
};
struct Inter{
ll l,r;
}inter[maxn];//inter表示第i个元素所管辖的区间
stack<node>stk;
struct tree{
ll mx,mi;
}tr[maxn*4];
void pushup(ll rt){
tr[rt].mx=max(tr[rt<<1].mx,tr[rt<<1|1].mx);
tr[rt].mi=min(tr[rt<<1].mi,tr[rt<<1|1].mi);
}
void build(ll l,ll r,ll rt){
if(l==r){
tr[rt].mx=sum[l];
tr[rt].mi=sum[l];
return;
}
ll mid=(l+r)>>1;
build(l,mid,rt<<1);
build(mid+1,r,rt<<1|1);
pushup(rt);
}
ll query_mx(ll ql,ll qr,ll l,ll r,ll rt){
if(l>=ql&&r<=qr){
return tr[rt].mx;
}
ll mid=(l+r)>>1,mx=-1e18;
if(mid>=ql)mx=max(query_mx(ql,qr,l,mid,rt<<1),mx);
if(mid<qr)mx=max(mx,query_mx(ql,qr,mid+1,r,rt<<1|1));
return mx;
}
ll query_mi(ll ql,ll qr,ll l,ll r,ll rt){
if(l>=ql&&r<=qr){
return tr[rt].mi;
}
ll mid=(l+r)>>1,mi=1e18;
if(mid>=ql)mi=min(query_mi(ql,qr,l,mid,rt<<1),mi);
if(mid<qr)mi=min(mi,query_mi(ql,qr,mid+1,r,rt<<1|1));
return mi;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
ll i,j,k,n,l,r;
cin>>n;
for(i=1;i<=n;i++){
cin>>a[i];
sum[i]+=sum[i-1]+a[i];
}
for(i=1;i<=n;i++){
if(stk.empty()||a[i]>=stk.top().val){
stk.push({a[i],i});
}
else{
r=stk.top().pos;
while(!stk.empty()&&a[i]<stk.top().val){
node u=stk.top();
inter[u.pos].r=r;
stk.pop();
}
stk.push({a[i],i});
}
}
if(!stk.empty())r=stk.top().pos;
while(!stk.empty()){
node u=stk.top();
inter[u.pos].r=r;
stk.pop();
}
for(i=n;i>=1;i--){
if(stk.empty()||a[i]>=stk.top().val){
stk.push({a[i],i});
}
else{
l=stk.top().pos;
while(!stk.empty()&&a[i]<stk.top().val){
node u=stk.top();
inter[u.pos].l=l;
stk.pop();
}
stk.push({a[i],i});
}
}
if(!stk.empty())l=stk.top().pos;
while(!stk.empty()){
node u=stk.top();
inter[u.pos].l=l;
stk.pop();
}
build(0,n,1);
ll ans=-1e18;
for(i=1;i<=n;i++){
if(a[i]>=0){
ll l=inter[i].l,r=inter[i].r;
ans=max(ans,a[i]*(sum[r]-sum[l-1]));
}
else{
ll l=inter[i].l,r=inter[i].r;
ll mi=query_mi(i,r,0,n,1);
ll mx=query_mx(l-1,i,0,n,1);
if(mx<0)mx=0;
ans=max(ans,a[i]*(mi-mx));
}
}
cout<<ans<<endl;
}