zoukankan      html  css  js  c++  java
  • 单调栈+线段树

    •  262144K
     

    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 le n le 5 imes 10 ^5n(1n5×105).

    Second line contains nn integers represent the array a (-10^5 le a_i le 10^5)a(105ai105).

    Output

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

    样例输入

    5
    1 2 3 4 5

    样例输出

    36

    陈你

    题意 : 给你 n 个元素,有正有负,要求你去寻找一个区间,要求区间中最小的元素乘以此元素所在的一段区间的和要最大,输出最大值

    思路分析:

      若元素全为正,显然就是单调栈的入门题了,但是现在元素有负的,因此需要换个角度去考虑

      借助单调栈,我们可以找到每个元素作为最小值所在的区间

      假设现在选取的一个元素是负的,那么我们是不就要找一段负的区间的和最小,乘起来才会使最大

      那么这个时候就可以借助前缀和,该位置右边的最小值减去左边的最大值即可,若左边最大值小于0,此时就不要减去

      用线段树去维护

      一直有个地方写错,就是单调栈找每个元素所在区间的地方

    代码示例:

    #define ll long long
    const ll maxn = 5e5+5;
    const ll mod = 1e9+7;
    const double eps = 1e-9;
    const double pi = acos(-1.0);
    const ll inf = 0x3f3f3f3f;
    
    ll n;
    ll a[maxn];
    ll lf[maxn], rf[maxn];
    struct pp
    {
        ll num, id;
    };
    struct pp sta[maxn];
    
    struct node
    {
        ll l, r;
        ll mm, mi;
    }t[maxn<<2];
    #define lson k<<1
    #define rson k<<1|1
    ll sum[maxn];
    void init(){
        ll top = 0;
        
        a[n+1] = -999999999;
        for(ll i = 1; i <= n+1; i++){
            while(top > 0 && sta[top].num > a[i]){
                rf[sta[top].id] = i-1;
                top--; 
            }
            sta[++top] = {a[i], i};
        }
        top = 0; 
        for(ll i = 1; i <= n+1; i++){
            ll pos = i;
            while(top > 0 && sta[top].num > a[i]){
                pos = sta[top].id;
                top--;
            }
            sta[++top] = {a[i], pos};
            lf[i] = pos;
        } 
    }
    
    void build(ll l, ll r, ll k){
        t[k].l = l, t[k].r = r;
        if (l == r){
            t[k].mm = t[k].mi = sum[l];
            return;
        }
        ll mid = (l+r)>>1;
        build(l, mid, lson);
        build(mid+1, r, rson);
        t[k].mm = max(t[lson].mm, t[rson].mm);
        t[k].mi = min(t[lson].mi, t[rson].mi);
    }
    
    ll qmax(ll l, ll r, ll k){
        ll ans = -1e18;
        if (l <= t[k].l && t[k].r <= r) {
            return t[k].mm;
        }
        ll mid = (t[k].l+t[k].r)>>1;
        if (l <= mid) ans = max(ans, qmax(l, r, lson));
        if (r > mid) ans = max(ans, qmax(l, r, rson));
        return ans;
    }
    
    ll qmin(ll l, ll r, ll k){
        ll ans = 1e18;
        if (l <= t[k].l && t[k].r <= r) {
            return t[k].mi;
        }
        ll mid = (t[k].l+t[k].r)>>1;
        if (l <= mid) ans = min(ans, qmin(l, r, lson));
        if (r > mid) ans = min(ans, qmin(l, r, rson));
        return ans;
    }
    
    
    void solve(){
        for(ll i = 1; i <= n; i++){
            sum[i] = sum[i-1]+a[i];
        }
        ll ans = 0;
        build(1, n, 1);
        for(ll i = 1; i <= n; i++){
            if (a[i]>0) ans = max(ans, (sum[rf[i]]-sum[lf[i]-1])*a[i]);
            else {
                ans = max(ans, a[i]*(qmin(i, rf[i], 1ll)-max(qmax(lf[i], i, 1ll), 0ll)));
            }
        }
        printf("%lld
    ", ans);
    }
    
    int main() {
        //freopen("in.txt", "r", stdin);
        //freopen("out.txt", "w", stdout);
        cin >> n;
        for(ll i = 1; i <= n; i++){
            scanf("%lld", &a[i]);
        }    
        init();
        solve();
        return 0;
    }
    

      

  • 相关阅读:
    C#中的Dictionary类,默认key是区分大小写的
    for循环的3个参数
    C#循环读取文件流,按行读取
    C#合并两个Dictionary的方法
    C#的Equals不区分大小写
    php的isset()和empty()区别
    css !important的作用
    mysql创建用户,并指定用户的权限(grant命令)
    解决安卓微信浏览器中location.reload 或者 location.href失效的问题
    【转】前端懒加载以及预加载
  • 原文地址:https://www.cnblogs.com/ccut-ry/p/10803287.html
Copyright © 2011-2022 走看看