2019暑假牛客多校訓練第四場 sequence(線段樹+單調棧)

鏈接:https://ac.nowcoder.com/acm/contest/884/C
來源:牛客網

題意很好懂。

【做法】

從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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章