链接:https://ac.nowcoder.com/acm/contest/884/C
题意:注意是多组输入。。。。第一行给出n,接下来给出数组a的n个元素和数组b的n个元素。在所有连续区间中,假设为[l,r],求数组a在该区间的最小值*数组b在该区间的和的最大值。
思路:用单调栈找出每个a[i]作用的范围,用线段树维护区间内前缀和的最大值和最小值。当a[i]<0时,求出[i,r[i]]区间内最小的前缀和(因为要选择的区间要包含a[i],这样a[i]才能起作用),再求出[l[i]-1,i-1](注意,这里是l[i]-1,因为是前缀和,左端点要-1,即pre[r]-pre[l-1]的意思。)中前缀和的最大值,这样取得区间的值才最大;同理,当a[i]>=0时,求出[i,r[i]]区间内最大的前缀和,再求出[l[i]-1,i-1]中前缀和的最小值,这样取得区间的值也最大。注意,建树是从0开始的(即build(0,n,1)),也是因为前缀和的原因。
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 3e6+10;
const ll inf = 1e18;
struct node
{
int l,r;
ll maxx,minn;
}tree[N<<2];
int l[N],r[N],a[N],b[N],sta[N],n,top;
ll pre[N],ans;
void getl()
{
top=0;
for(int i=1;i<=n;i++)
{
while(top!=0&&a[sta[top]]>=a[i]) top--;
if(top) l[i]=sta[top]+1;
else l[i]=1;
sta[++top]=i;
}
}
void getr()
{
top=0;
for(int i=n;i>=1;i--)
{
while(top!=0&&a[sta[top]]>=a[i]) top--;
if(top) r[i]=sta[top]-1;
else r[i]=n;
sta[++top]=i;
}
}
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);
return ;
}
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=pre[l];
return ;
}
int m=(l+r)>>1;
build(l,m,cur<<1);
build(m+1,r,cur<<1|1);
pushup(cur);
return ;
}
ll querymax(int l,int r,int cur)
{
ll res=-inf;
if(l<=tree[cur].l&&tree[cur].r<=r)
{
return tree[cur].maxx;
}
if(l<=tree[cur<<1].r) res=max(res,querymax(l,r,cur<<1));
if(r>=tree[cur<<1|1].l) res=max(res,querymax(l,r,cur<<1|1));
return res;
}
ll querymin(int l,int r,int cur)
{
ll res=inf;
if(l<=tree[cur].l&&tree[cur].r<=r)
{
return tree[cur].minn;
}
if(l<=tree[cur<<1].r) res=min(res,querymin(l,r,cur<<1));
if(r>=tree[cur<<1|1].l) res=min(res,querymin(l,r,cur<<1|1));
return res;
}
int main(void)
{
while(~scanf("%d",&n))
{
ans=-inf;
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=n;i++)
{
scanf("%d",&b[i]);
pre[i]=pre[i-1]+b[i];
}
getl(); getr();
build(0,n,1);
for(int i=1;i<=n;i++)
{
if(a[i]<0)
ans=max(ans,(ll)a[i]*(querymin(i,r[i],1)-querymax(l[i]-1,i-1,1)));
else if(a[i]>0)
ans=max(ans,(ll)a[i]*(querymax(i,r[i],1)-querymin(l[i]-1,i-1,1)));
else ans=max(ans,0LL);
}
printf("%lld\n",ans);
}
return 0;
}
/*
3
1 -1 1
1 2 3
*/