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;
    }
  • 相关阅读:
    超酷的元素周期表
    TestLink在线Excel用例转换xml
    我也学习JAVA多线程-join
    request.getSession(true/false)的区别
    nginx location配置详细解释
    RestTemplate--解决中文乱码
    扇贝-每日一句
    Hexo博客系列(三)-将Hexo v3.x个人博客发布到GitLab Pages
    C程序的内存分区(节选自黑马训练营day1)
    CodeBlocks更换界面主题界面、汉化及去掉注释及字符串的下划线(汉化包的链接来自本站的BeatificDevin大神)
  • 原文地址:https://www.cnblogs.com/FrankChen831X/p/10784963.html
Copyright © 2011-2022 走看看