【单调栈+线段树】多次询问输出(区间最大和*区间最小值)max 南昌邀请赛I题 Max Answer

南昌邀请赛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(1≤n≤5×1e5).

Second line contains nn integers represent the array a(−1e5≤ai​≤1e5).

Output

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

样例输入复制

5
1 2 3 4 5

样例输出复制

36

用前缀和建线段树

用单调栈保留第i个数作为最小值的左右界限

每一个数扫一遍

如果a[i]>=0就是此段和*a[i]

如果a[i]<0就是找pre中 (i 到 r 的最小值  -  l 到 i 的最大值) * a[i]

更新最大值

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 5e5+5;
ll a[maxn];
int L[maxn], R[maxn], st[maxn];
ll pre[maxn];
struct node
{
    ll mi,ma;
}tree[maxn*4];

void build(int l,int r,int rt)
{
    if(l==r)
    {
        tree[rt].mi=tree[rt].ma=pre[l];
        return;
    }
    int mid=(l+r)/2;
    build(l,mid,rt*2);
    build(mid+1,r,rt*2+1);
    tree[rt].ma=max(tree[2*rt].ma,tree[2*rt+1].ma);
    tree[rt].mi=min(tree[2*rt].mi,tree[2*rt+1].mi);
}

ll query(int x,int y,int l,int r,int rt,int flag)
{
    if(flag==0)//取最小值
    {
        if(x<=l&&r<=y)
            return tree[rt].mi;
        int mid=(l+r)/2;
        ll left=1e18,right=1e18;
        if(x<=mid)
            left=min(left,query(x,y,l,mid,2*rt,0));
        if(y>mid)
            right=min(right,query(x,y,mid+1,r,2*rt+1,0));
        return min(left,right);
    }
    else //取最大值
    {
        if(x<=l&&r<=y)
            return tree[rt].ma;
        int mid=(l+r)/2;
        ll left=-1e18,right=-1e18;
        if(x<=mid)
            left=max(left,query(x,y,l,mid,2*rt,1));
        if(y>mid)
            right=max(right,query(x,y,mid+1,r,2*rt+1,1));
        return max(left,right);
    }
}

int main()
{
    int n;
    scanf("%d", &n);
    pre[0]=0;
    for(int i = 1; i <= n; i++)
    {
        scanf("%lld", &a[i]);
        pre[i]=pre[i-1]+a[i];
    }

    int top = 0;
    for(int i = 1; i <= n; i++)
    {
        while(top && a[st[top-1]] >= a[i]) top--;
        L[i] = (top==0) ? 0 : st[top-1];
        st[top++] = i;
    }
    top = 0;
    for(int i = n; i >= 1; i--)
    {
        while(top && a[st[top-1]] >= a[i]) top--;
        R[i] = (top==0) ? (n+1) : st[top-1];
        st[top++] = i;
    }

    for(int i = 1; i <= n; i++)
    {
        L[i]++,R[i]--;
    }

    build(1,n,1);
    ll ans = 0;
    for(int i=1;i<=n;i++)
    {
        if(a[i]>=0)
        {
            ll q=(pre[R[i]]-pre[L[i]-1])*a[i];
            ans=max(ans,q);
        }
        else
        {
            ll q=(query(i,R[i],1,n,1,0)-query(L[i],i,1,n,1,1))*a[i];
            ans=max(ans,q);
        }
    }
    printf("%lld\n",ans);

    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41037114/article/details/89433186