• 南昌邀请赛I.Max answer 单调栈+线段树


    题目链接:https://nanti.jisuanke.com/t/38228

    Alice has a magic array. She suggests that the value of a interval is equal to the sum of the values in the interval, multiplied by the smallest value in the interval.

    Now she is planning to find the max value of the intervals in her array. Can you help her?

    Input

    First line contains an integer n(1n5×105).

    Second line contains nn integers represent the array a (105ai105).

    Output

    One line contains an integer represent the answer of the array.

    样例输入

    5
    1 2 3 4 5

    样例输出

    36

    题目定义区间的值为区间之和乘以区间的最小值,要你求出最大的区间值
    求出前缀和sum并用线段树维护,再用单调栈求出第i个点之前第一个比他小的点l[i](下标),以及i之后第一个比他小的点r[i](下标)
    枚举每个点,如果第i个点非负,区间值即为(sum[r[i]]-sum[l[i]-1])*a[i]
    如果第i个点为负数则在[l[i],r[i]]内找到最小的区间和并乘以a[i]即为区间值
    #include<iostream>
    #include<stack>
    using namespace std;
    #define maxn 500005
    #define ls l,mid,rt<<1
    #define rs mid+1,r,rt<<1|1
    #define ll long long
    #define inf 0x3f3f3f3f
    int n,l[maxn],r[maxn];
    ll a[maxn],b[maxn],pre[maxn],sum[2][maxn<<2];
    void pushup(int rt)
    {
        sum[0][rt]=max(sum[0][rt<<1],sum[0][rt<<1|1]);
        sum[1][rt]=min(sum[1][rt<<1],sum[1][rt<<1|1]);
    }
    void build(int l,int r,int rt)
    {
        if(l==r)
        {
            sum[0][rt]=sum[1][rt]=pre[l];
            return ;
        }
        int mid=l+r>>1;
        build(ls);
        build(rs);
        pushup(rt);
    }
    ll q1(int L,int R,int l,int r,int rt)
    {
        if(L<=l&&R>=r)return sum[0][rt];
        int mid=l+r>>1;
        ll ans=-inf;
        if(L<=mid)ans=max(ans,q1(L,R,ls));
        if(R>mid)ans=max(ans,q1(L,R,rs));
        return ans;
    }
    ll q2(int L,int R,int l,int r,int rt)
    {
        if(L<=l&&R>=r)return sum[1][rt];
        int mid=l+r>>1;
        ll ans=inf;
        if(L<=mid)ans=min(ans,q2(L,R,ls));
        if(R>mid)ans=min(ans,q2(L,R,rs));
        return ans;
    }
    int main()
    {
        cin>>n;
        pre[0]=0;
        for(int i=1;i<=n;i++)
        {
            cin>>a[i];
            pre[i]=pre[i-1]+a[i];
        }
        build(1,n,1);
        stack<int>s;
        for(int i=1;i<=n;i++)
        {
            while(s.size()&&a[s.top()]>=a[i])s.pop();
            if(s.empty())l[i]=1;
            else l[i]=s.top()+1;
            s.push(i);
        }
        while(!s.empty())s.pop();
        for(int i=n;i>=1;i--)
        {
            while(s.size()&&a[s.top()]>=a[i])s.pop();
            if(s.empty())r[i]=n;
            else r[i]=s.top()-1;
            s.push(i);
        }
        ll ans=-inf;
        for(int i=1;i<=n;i++)
        {
            if(a[i]>=0)ans=max(ans,(pre[r[i]]-pre[l[i]-1])*a[i]);
            else
            {
                ll maxx,minn;//maxx为[l[i]-1,i-1]的最大前缀和,minn为[i,r[i]]的最小前缀和,最小减最大负的就最多 
                maxx=q1(max(l[i]-1,1),max(i-1,l[i]),1,n,1);
                minn=q2(i,r[i],1,n,1);
                ans=max(ans,(minn-maxx)*a[i]);
            }
        }
        cout<<ans<<endl;
        return 0;
    }
  • 相关阅读:
    单表查询
    解读python中SocketServer源码
    C++实训(2.3)
    C++实训(2.2)
    C++实训(2.1)
    C++实训(1.3)
    C++实训(1.1)
    顺序表的实现,在vs2019上运行成功
    p243_5(3)
    自考新教材-p176_5(2)
  • 原文地址:https://www.cnblogs.com/chen99/p/10771394.html
Copyright © 2020-2023  润新知