链接:https://ac.nowcoder.com/acm/contest/884/C
来源:牛客网

题意很好懂。

2019暑假牛客多校训练第四场 sequence(线段树+单调栈)_预处理

【做法】

从a数组中枚举以当前a[i]为最小值时能左右包括的最大范围,这是单调栈的常用做法了。维护递增的栈就可以了。

预处理b的前缀和用线段树维护区间最大值、最小值。

准备工作做完后开始求答案,枚举a[i],若a[i]>0 ,那就从i到r[i]区间内找最大的前缀和rsum,从l[i]~i-1找最小的前缀和lsum,l[i]和r[i]是之前单调栈预处理得到的i位置能左右扩展的最大区间。

【注】:这个题十分卡常,我这份代码是有时能A,有时不能A。。。

赛后交了5发A的。赛时没过。。。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=3e6+1;
int n;
ll a[N],stmax[N*4],stmin[N*4];
int l[N],r[N],b[N],indexst[N],tail;
void up(int id,int l,int r)
{
    if(l==r)
    {
        stmax[id]=a[l];
        stmin[id]=a[l];
        return ;
    }
    int mid=l+r>>1;
    up(id<<1,l,mid);
    up(id<<1|1,mid+1,r);
    stmax[id]=max(stmax[id<<1],stmax[id<<1|1]);
    stmin[id]=min(stmin[id<<1],stmin[id<<1|1]);
}
void init()
{
    for(int i=1;i<=n;i++) a[i]=a[i-1]+a[i];
    up(1,1,n);
    for(int i=1;i<=n;i++)
    {
        while(tail>1&&b[i]<=b[indexst[tail]]) --tail;
        if(tail==0) l[i]=1;
        else
            l[i]=indexst[tail]+1;
        indexst[++tail]=i;
    }
    tail=0;
    for(int i=n;i>=1;i--)
    {
        while(tail>0&&b[i]<=b[indexst[tail]]) --tail;
        if(tail==0){
                r[i]=n;
        }
        else
            r[i]=indexst[tail]-1;
        indexst[++tail]=i;
    }
}
ll querymax(int id,int l,int r,int ql,int qr)
{
    if(ql<=l&&r<=qr) return stmax[id];
    int mid=l+r>>1;
    ll ans=-0x3f3f3f3f3f3f3f3f;
    if(ql<=mid) ans=max(ans,1ll*querymax(id<<1,l,mid,ql,qr));
    if(qr>mid) ans=max(ans,1ll*querymax(id<<1|1,mid+1,r,ql,qr));
    return ans;
}

ll querymin(int id,int l,int r,int ql,int qr)
{
    if(ql<=l&&r<=qr) return stmin[id];
    int mid=l+r>>1;
    ll ans=0x3f3f3f3f3f3f3f3f;
    //stmin[id]=ans;
    if(ql<=mid) ans=min(ans,1ll*querymin(id<<1,l,mid,ql,qr));
    if(qr>mid) ans=min(ans,1ll*querymin(id<<1|1,mid+1,r,ql,qr));
    return ans;
}

ll rsum,lsum;
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;++i) scanf("%d",&b[i]);
    for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
    if(n==1){
        printf("%lld\n",a[1]*b[1]);
        return 0;
    }
    init();
    ll ans=-0x3f3f3f3f3f3f3f3f;
    for(int i=1;i<=n;i++)
    {
        if(b[i]<0)
        {
            rsum=querymin(1,1,n,i,r[i]);
            int ql=max(1,l[i]-1),qr=max(i-1,1);
            lsum=querymax(1,1,n,ql,qr);
            ans=max(ans,(rsum-lsum)*b[i]);
        }
        else if(b[i]>0)
        {
            rsum=querymax(1,1,n,i,r[i]);
            int ql=max(1,l[i]-1),qr=max(i-1,1);
            lsum=querymin(1,1,n,ql,qr);
            ans=max(ans,(rsum-lsum)*b[i]);
        }
        else ans=ans>0?ans:0;
    }
    printf("%lld\n",ans);
    return 0;
}