zoukankan      html  css  js  c++  java
  • 南昌邀请赛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;
    }
  • 相关阅读:
    Android 如何处理崩溃的异常
    体验下Xcode5与ios7
    IOS 改变导航栏返回按钮的标题
    android之HttpURLConnection
    android异步加载图片
    android 从服务器上获取APK下载安装
    android AsyncTask异步下载并更新进度条
    android 四种堆状态
    Windows Azure 的开源 DNA
    mysql 只给更新表的某个字段的授权
  • 原文地址:https://www.cnblogs.com/chen99/p/10771394.html
Copyright © 2011-2022 走看看