zoukankan      html  css  js  c++  java
  • 2019南昌网络赛-I(单调栈+线段树)

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

    题意:定义一段区间的值为该区间的和×该区间的最小值,求给定数组的最大的区间值。

    思路:比赛时还不会线段树,和队友在这题上弄了3小时,思路大体都是对的,但就是没法实现。这几天恶补线段树。

       首先可以利用单调栈来查找满足a[i]为最小值的最大区间L[i]~R[i]。然后利用线段树求一个段的和sum、最小前缀lsum和最小后缀rsum。然后遍历a[i]:

        a[i]>0:最优为sum(L[i],R[i])*a[i]

        a[i]<0:最优为(sumr(L[i],i)+suml(i,R[i]-i)*a[i]

       这里用线段树查询可以用传递引用来求lsum和rsum,因为我们查询一段区间是从左向右查询的,或者可以用三个全局变量Sum、Lsum、Rsum记录当前已找到的区间的对应属性也行。

    AC代码:

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int maxn=500005;
    typedef long long LL;
    
    struct node{
        int l,r;
        LL sum,lsum,rsum;  //sum为区间和,lsum最小前缀,rsum最小后缀
    }tr[maxn<<2];
    //L[i]~R[i]为满足a[i]为最小的最大区间
    int n,p,a[maxn],L[maxn],R[maxn],stk[maxn];
    LL ans;
    
    node gets(node a,node b){
        node t;
        t.l=a.l,t.r=b.r;
        t.sum=a.sum+b.sum;
        t.lsum=min(a.lsum,a.sum+b.lsum);
        t.rsum=min(b.rsum,b.sum+a.rsum);
        return t;
    }
    
    void build(int v,int l,int r){
        tr[v].l=l,tr[v].r=r;
        if(l==r){
            tr[v].sum=a[r];
            tr[v].lsum=min(a[r]*1LL,0LL);
            tr[v].rsum=min(a[r]*1LL,0LL);
            return;
        }
        int mid=(l+r)>>1;
        build(v<<1,l,mid);
        build(v<<1|1,mid+1,r);
        tr[v]=gets(tr[v<<1],tr[v<<1|1]);
    }
    
    void query(node &x,int v,int l,int r){
        if(l<=tr[v].l&&r>=tr[v].r){
            x=gets(x,tr[v]);
            return;
        }
        int mid=(tr[v].l+tr[v].r)>>1;
        if(l<=mid) query(x,v<<1,l,r);
        if(r>mid) query(x,v<<1|1,l,r);
    }
    
    int main(){
        scanf("%d",&n);
        for(int i=1;i<=n;++i)
            scanf("%d",&a[i]);
        a[0]=a[n+1]=0xcfcfcfcf;
        stk[p=0]=0;   //利用单调栈求L[i],R[i]
        for(int i=1;i<=n;++i){
            while(a[stk[p]]>=a[i]) --p;
            L[i]=stk[p]+1;
            stk[++p]=i;
        }
        stk[p=0]=n+1;
        for(int i=n;i>=1;--i){
            while(a[stk[p]]>=a[i]) --p;
            R[i]=stk[p]-1;
            stk[++p]=i;
        }
        build(1,1,n);
        for(int i=1;i<=n;++i){
            if(a[i]>0){
                node t;
                t.sum=t.lsum=t.rsum=0;
                query(t,1,L[i],R[i]);
                if(a[i]*t.sum>ans) ans=a[i]*t.sum;
            }
            else if(a[i]<0){
                LL tmp=0;
                node t;
                t.sum=t.lsum=t.rsum=0;
                query(t,1,L[i],i);
                tmp+=t.rsum;
                t.sum=t.lsum=t.rsum=0;
                query(t,1,i,R[i]);
                tmp+=t.lsum;
                tmp-=a[i];
                if(tmp*a[i]>ans) ans=tmp*a[i];
            }
        }
        printf("%lld
    ",ans);
        return 0;
    }
  • 相关阅读:
    Legacy(点对线段有路走,线段向点有路走,线段树走dij)
    G. Death DBMS(查询每个主串和n个模板串匹配后val最大值,支持单点更新)
    2020 CCPC Wannafly Winter Camp Day5 J Xor on Figures(矩阵转01串,统计01串异或种类)
    zoj3988(自己集合和自己集合匹配)
    2020 CCPC Wannafly Winter Camp Day7 A(求任何子序列中相邻范围内数的个数的总和)
    hdu6241(给定树中向上向下限制求最小可能个数)
    hdu6230(求限制条件的回文个数,利用manacher+BIT求解)
    NOIP 2020 游记
    分散层叠算法学习笔记
    代理模式
  • 原文地址:https://www.cnblogs.com/FrankChen831X/p/10784963.html
Copyright © 2011-2022 走看看