• [未知OJ]山海经 题解 线段树


    题意:给出一个数列a(n<=1e5),每次询问区间[l..r]的最大连续子段和,以及这个连续子段的两个端点。如果有多组解,则输出左端点最小的,如果仍有多组解,则输出右端点最小的解。

    此题有简单版

    这题毒瘤就毒瘤在求这两个端点。对于线段树的每个节点,除了记录区间和,前缀最大和,后缀最大和,最大连续子段和,还要分别记录前缀最大和,后缀最大和,最大连续子段和的端点,似乎这题码量算少的?

    #include<bits/stdc++.h>
    using namespace std;
    #define scanf a1234=scanf
    int a1234;
    
    const int mxn=1e5+3;int n,T,a[mxn];
    struct tourist{
        int lnum,rnum,sum,num,ll,rr,ln,rn;
    //ll是lnum的端点 rr是rnum的端点 ln rn是num的端点
        inline void pr(int l,int r){
            printf("%d %d %d %d %d %d %d %d %d %d\n",l,r,lnum,rnum,sum,num,ll,rr,ln,rn);
        }
    };
    
    #define mid ((l+r)>>1)
    class segm{
        public:
        tourist tr[mxn*4];
        inline void Build(int x,int l,int r){
            if(l==r)return tr[x]={a[l],a[l],a[l],a[l],l,l,l,l},void();
            Build(x*2,l,mid),Build(x*2+1,mid+1,r);
            up(x);
        }
        inline void up(int x){
            tr[x]=merge(tr[x*2],tr[x*2+1]);
        }
        inline tourist merge(tourist &a,tourist &b){
            static tourist res;
            res.sum=a.sum+b.sum;
            int aa=a.lnum,bb=a.sum+b.lnum;
            if(aa>=bb)res.lnum=aa,res.ll=a.ll;else res.lnum=bb,res.ll=b.ll;
            aa=b.rnum,bb=b.sum+a.rnum;
            if(bb>=aa)res.rnum=bb,res.rr=a.rr;else res.rnum=aa,res.rr=b.rr;
            
            
            aa=a.num,bb=b.num;
            if(aa>=bb)res.num=aa,res.ln=a.ln,res.rn=a.rn;
            else      res.num=bb,res.ln=b.ln,res.rn=b.rn;
            aa=a.rnum+b.lnum; int ll=a.rr,rr=b.ll;
            if(aa>res.num|| (aa==res.num&&ll<res.ln) /*|| (aa==res.num&&ll==res.ln&&rr<res.rn)*/)res.num=aa,res.ln=ll,res.rn=rr;
            return res;
        }
        inline tourist qask(int x,int l,int r,int lc,int rc){   
            if(lc<=l&&r<=rc)return tr[x];
            if(lc>mid)return qask(x*2+1,mid+1,r,lc,rc);
            if(rc<=mid)return qask(x*2,l,mid,lc,rc);
            tourist lres=qask(x*2,l,mid,lc,rc),rres=qask(x*2+1,mid+1,r,lc,rc);
            return merge(lres,rres);
        }
    }seg;
    #undef mid
    
    int main(){
        scanf("%d%d",&n,&T);for(int i=1;i<=n;++i)scanf("%d",a+i);
        seg.Build(1,1,n);
        while(T--){
           int l,r;scanf("%d%d",&l,&r);
           static tourist tql; tql=seg.qask(1,1,n,l,r);
           printf("%d %d %d\n",tql.ln,tql.rn,tql.num);
        }
        return 0;
    }
    
  • 相关阅读:
    XP系统下快速切换ip的bat脚本配置
    Spring学习札记
    hibernate防止sql注入
    重载,继承,重写和多态的区别:
    Oracle Sql基础
    Android开发——利用Cursor+CursorAdapter实现界面实时更新
    Android开发——09Google I/O之让Android UI性能更高效(1)
    Android开发——MediaProvider源码分析(2)
    Android开发——Android搜索框架(二)
    [转]activity的启动方式(launch mode)
  • 原文地址:https://www.cnblogs.com/happyguy/p/13379620.html
Copyright © 2020-2023  润新知