南昌网络赛 I. Max answer (单调栈 + 线段树)

https://nanti.jisuanke.com/t/38228

题意
给你一个序列,对于每个连续子区间,有一个价值,等与这个区间和×区间最小值,
求所有子区间的最大价值是多少。

分析:我们先用单调栈预处理 区间 [L[i] , R[i] ] 最小值为a[i] , 的L[i] , R[i] ;

首先我们明白 , 如果a[i] >0 那 [L[i] , R[i] ] , 里面的数都是正数 , 所以应该全选 ;

a[i] < 0 , 那我们 应该在[L[i]-1 , i-1] 这里面找到前缀和最大 , 在[i,R[i]] 这里找到前缀和最小

这样的区间和才是最大

我。。。比赛的时候被自己秀死 , 判断a[i] >0 竟然也用了线段树的做法 , 导致边界没有控制好

#include <iostream>
#include <string.h>
#include <algorithm>
#include <stdio.h>
#include <math.h>
#include <queue>
#define MAXN 500001
#define inf 0x3f3f3f3f

using namespace std;
const int N=500001;
typedef long long ll;

int a[N],L[N],R[N],s[N],top;
ll sum[N],ans=-0x7f7f7f7f,n,h[N];
ll l=1,r=1;
struct node{
    int l,r;//区间[l,r]


    ll mx; //区间最大值
    ll mn; //区间最小值
}tree[MAXN<<2];//一定要开到4倍多的空间

void pushup(int index){

    tree[index].mx = max(tree[index<<1].mx,tree[index<<1|1].mx);
    tree[index].mn = min(tree[index<<1].mn,tree[index<<1|1].mn);
}

int cnt;
void build(int l,int r,int index){
    tree[index].l = l;
    tree[index].r = r;

    if(l == r){
       // scanf("%d",&tree[index].sum);
        tree[index].mn = tree[index].mx =sum[++cnt];
        return ;
    }
    int mid = (l+r)>>1;
    build(l,mid,index<<1);
    build(mid+1,r,index<<1|1);
    pushup(index);
}

ll queryMIN(int l,int r,int index){
    if(l <= tree[index].l && r >= tree[index].r){
        //return tree[index].sum;

    return tree[index].mn;
    }

    int mid = (tree[index].l+tree[index].r)>>1;


    ll Min =0x7f7f7f7f;
    if(l <= mid){

       // Max = max(query(l,r,index<<1),Max);
        Min = min(queryMIN(l,r,index<<1),Min);
    }
    if(r > mid){

      //  Max = max(query(l,r,index<<1|1),Max);
        Min = min(queryMIN(l,r,index<<1|1),Min);
    }
    //return ans;

    return Min;
    //return Min;
}
ll queryMAX(int l,int r,int index){
    if(l <= tree[index].l && r >= tree[index].r){
        //return tree[index].sum;
        return tree[index].mx;
        //return tree[index].mn;
    }

    int mid = (tree[index].l+tree[index].r)>>1;

    ll Max = -0x7f7f7f7f;

    if(l <= mid){

        Max = max(queryMAX(l,r,index<<1),Max);
       // Min = min(query(l,r,index<<1),Min);
    }
    if(r > mid){

        Max = max(queryMAX(l,r,index<<1|1),Max);
        //Min = min(query(l,r,index<<1|1),Min);
    }
    //return ans;

    return Max;
    //return Min;
}
int main()
{


    ios::sync_with_stdio(false);
    cin>>n;
    memset(sum,0,sizeof(sum));
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
        sum[i]=sum[i-1]+a[i];

    }
    build(1,n+1,1);



    top=0;
    for(int i=1;i<=n;i++)
    {
        while(top&&a[s[top]]>=a[i])
            --top;
        L[i]=(top==0?1:s[top]+1);
        s[++top]=i;
    }
    top=0;
    for(int i=n;i>=1;i--)
    {
        while(top&&a[s[top]]>=a[i])
            --top;
        R[i]=(top==0?n:s[top]-1);
        s[++top]=i;
    }
   // cout<<queryMIN(2,2,1)<<endl;
    for(int i=1;i<=n;i++)
    {
        ll temp;
        if(a[i]>0)
        {

       temp =(sum[R[i]] - sum[L[i]-1])*a[i];
//       cout<<L[i]<<" "<<R[i]<<endl;
//       cout<<queryMAX(i,R[i],1)<<" "<<queryMIN(L[i]-1,i-1,1)<<endl;
        }
        else if(a[i]<0)
        {

                if(L[i]==1 && queryMAX(max(1,L[i]-1),max(1,i-1),1)<0)
                    temp=(queryMIN(i,R[i],1))*a[i];
                else
                temp =(queryMIN(i,R[i],1)-queryMAX(max(1,L[i]-1),max(1,i-1),1))*a[i];

//       cout<<queryMAX(L[i]-1,i-1,1)<<" "<<queryMIN(i,R[i],1)<<endl;

        }
        else if(a[i]==0)
            temp=0;
//        else if(a[i]<0)
//        {
//            temp=(queryMIN(R[i],i,1) - queryMAX(L[i],i,1))*a[i];
//        }
        if(temp>ans) {ans=temp;}
    }

    cout<<ans<<endl;
}
View Code
原文地址:https://www.cnblogs.com/shuaihui520/p/10745122.html