题目链接:https://ac.nowcoder.com/acm/contest/884#question
题意:answer max1≤l≤r≤n{min(al…r)×sum(bl…r)}
题解:枚举a的每一个位置,以这个位置为最小值,找到左右边界,用单调栈就可以了,线段树维护b数组的前缀和,如果这个位置a是小于0的,那么就保证在可取区间内使得sum(bl-r)最小, 也就是右边取个前缀最小的,左边取个前缀最大的,反之亦然。这个题和南昌邀请赛网络赛的题是一样的:https://blog.csdn.net/mmk27_word/article/details/89421521
#include<bits/stdc++.h>
using namespace std;
const int N=3e6+10;
typedef long long ll;
struct node
{
int l,r;
ll maxx,minn;
}tree[N<<2];
ll sum[N],a[N],b[N];
int n;
int l[N],r[N];
void pushup(int cur)
{
tree[cur].maxx=max(tree[cur<<1].maxx,tree[cur<<1|1].maxx);
tree[cur].minn=min(tree[cur<<1].minn,tree[cur<<1|1].minn);
}
void build(int l,int r,int cur)
{
tree[cur].l=l;
tree[cur].r=r;
if(l==r)
{
tree[cur].maxx=tree[cur].minn=sum[l];
return;
}
int mid=(r+l)>>1;
build(l,mid,cur<<1);
build(mid+1,r,cur<<1|1);
pushup(cur);
// cout<<l<<" "<<r<<" "<<tree[cur].l<<" "<<tree[cur].maxx<<" "<<tree[cur].minn<<endl;
}
ll querymax(int pl,int pr,int cur)
{
if(pl<=tree[cur].l&&tree[cur].r<=pr)
{
return tree[cur].maxx;
}
ll res=-1e18;
if(pl<=tree[cur<<1].r) res=max(res,querymax(pl,pr,cur<<1));
if(pr>=tree[cur<<1|1].l) res=max(res,querymax(pl,pr,cur<<1|1));
return res;
}
ll querymin(int pl,int pr,int cur)
{
if(pl<=tree[cur].l&&tree[cur].r<=pr)
{
return tree[cur].minn;
}
ll res=1e18;
if(pl<=tree[cur<<1].r) res=min(res,querymin(pl,pr,cur<<1));
if(pr>=tree[cur<<1|1].l) res=min(res,querymin(pl,pr,cur<<1|1));
return res;
}
int main()
{
while(~scanf("%d",&n))
{
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
}
for(int i=1;i<=n;i++)
{
scanf("%lld",&b[i]);
sum[i]=sum[i-1]+b[i];
}
stack<int> s;
for(int i=1;i<=n;i++)
{
while(!s.empty() && a[s.top()] >= a[i]) s.pop();
if(s.empty()) l[i]=0;
else
{
l[i]=s.top();
// cout<<s.top()<<" "<<a[s.top()]<<" " <<a[i]<<" "<<(!s.empty() && a[s.top()] >= a[i])<<endl;
}
s.push(i);
// cout<<l[i]<<endl;
}
while(!s.empty()) s.pop();
for(int i=n;i>=1;i--)
{
while(!s.empty() && a[s.top()] >= a[i]) s.pop();
if(s.empty()) r[i]=n;
else r[i]=s.top()-1;
// cout<<r[i]<<endl;
s.push(i);
}
build(0,n,1);
ll ans=-1e18,cnt;
for(int i=1;i<=n;i++)
{
cnt=a[i];
// cout<<l[i]<<" "<<i-1<<" "<<i<<" "<<r[i]<<endl;
if(cnt>0) cnt=cnt*(querymax(i,r[i],1)-querymin(l[i],i-1,1));
else cnt=cnt*(querymin(i,r[i],1)-querymax(l[i],i-1,1));
// cout<<cnt<<endl;
ans=max(ans,cnt);
}
printf("%lld\n",ans);
}
return 0;
}