sequence
题意:求一段区间里面a数组的最小值乘b数组的区间和,求的该值的最大值。
思路:单调栈维护ai左右延伸区间,线段树维护b数组前缀和数组的最大最小值。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=3e6+5;
ll sum[maxn],mx[maxn*4],mn[maxn*4];
int a[maxn],b[maxn];
int l[maxn],r[maxn];
void build(int o,int l,int r){
if(l==r){
mn[o]=mx[o]=sum[l];
return;
}
int m=(l+r)>>1;
build(o*2,l,m);
build(o*2+1,m+1,r);
mn[o]=min(mn[o*2],mn[o*2+1]);
mx[o]=max(mx[o*2],mx[o*2+1]);
}
ll qumn(int o,int l,int r,int ql,int qr){
if(ql<=l&&qr>=r)
return mn[o];
int m=(l+r)>>1;
ll ans=1e18;
if(ql<=m)
ans=min(ans,qumn(o*2,l,m,ql,qr));
if(qr>m)
ans=min(ans,qumn(o*2+1,m+1,r,ql,qr));
return ans;
}
ll qumx(int o,int l,int r,int ql,int qr){
if(ql<=l&&qr>=r)
return mx[o];
int m=(l+r)>>1;
ll ans=-1e18;
if(ql<=m)
ans=max(ans,qumx(o*2,l,m,ql,qr));
if(qr>m)
ans=max(ans,qumx(o*2+1,m+1,r,ql,qr));
return ans;
}
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]),l[i]=1,r[i]=n;
ll ans=-1e18;
sum[0]=0;
for(int i=1;i<=n;i++){
scanf("%d",&b[i]);
if(i!=1)
sum[i]=sum[i-1]+b[i];
else sum[i]=b[i];
ans=max(ans,1ll*a[i]*b[i]);
}
build(1,0,n);
for(int i=1;i<=n;i++){
l[i]=i;
while(l[i]>1&&a[l[i]-1]>=a[i])
l[i]=l[l[i]-1];
}
for(int i=n;i>=1;i--){
r[i]=i;
while(r[i]<n&&a[r[i]+1]>=a[i])
r[i]=r[r[i]+1];
}
for(int i=1;i<=n;i++){
ll mn,mx;
if(a[i]>=0){
mx=qumx(1,0,n,i,r[i]);
mn=qumn(1,0,n,l[i]-1,i-1);
ans=max(ans,1ll*a[i]*(mx-mn));
}
else {
mx=qumn(1,0,n,i,r[i]);
mn=qumx(1,0,n,l[i]-1,i-1);
ans=max(ans,1ll*a[i]*(mx-mn));
}
}
printf("%lld\n",ans);
}