zoukankan      html  css  js  c++  java
  • codevs 3981 动态最大子段和

    3981 动态最大子段和

     
     题目等级 : 钻石 Diamond
     
    题目描述 Description

    题目还是简单一点好... 

    有n个数,a[1]到a[n]。

    接下来q次查询,每次动态指定两个数l,r,求a[l]到a[r]的最大子段和。

    子段的意思是连续非空区间。

    输入描述 Input Description

    第一行一个数n。

    第二行n个数a[1]~a[n]。

    第三行一个数q。

    以下q行每行两个数l和r。

    输出描述 Output Description

    q行,每行一个数,表示a[l]到a[r]的最大子段和。

    样例输入 Sample Input

    7
    2 3 -233 233 -23 -2 233
    4
    1 7
    5 6
    2 5
    2 3

    样例输出 Sample Output

    441
    -2
    233
    3

    数据范围及提示 Data Size & Hint

    对于50%的数据,q*n<=10000000。

    对于100%的数据,1<=n<=200000,1<=q<=200000。

    a[1]~a[n]在int范围内,但是答案可能超出int范围。

    数据保证1<=l<=r<=n。

    空间128M,时间1s。

    线段树求GSS模板题

    一、一段长的区间的 GSS 有三种情况:
    >1 完全在左子区间
    >2 完全在右子区间
    >3 横跨左右区间

    二、需维护的信息:

    max 区间GSS  ——用来更新情况1、2

    max_l 区间左端点开始的GSS——用来更新情况3

    max_r 区间右端点开始的GSS——用来更新情况3

    sum 区间和——用来更新max_l,max_r

    三、建树

    1、初始化:区间需维护的信息最初都赋为输入值

    2、合并区间信息

        max:3中情况中的最大值

        max_l:左区间的max_l, 左区间的sum+右区间max_l  取大

        max_r 同理 

    四、查询

    情况1、2很简单

    情况3的合并与上面的合并区间信息同理

    #include<cstdio>
    #include<algorithm>
    #include<iostream>
    using namespace std;
    int n,m,opl,opr,cnt;
    struct node
    {
        int l,r;
        long long max,max_l,max_r,sum;
    }e[4000001];
    void query(int k,long long & ans,long long & ans_l,long long & ans_r)
    {
        if(e[k].l>=opl&&e[k].r<=opr)
        {
            ans=e[k].max;
            ans_l=e[k].max_l;
            ans_r=e[k].max_r;
            return;
        }
        int mid=e[k].l+e[k].r>>1;
        if(opr<=mid) query(k<<1,ans,ans_l,ans_r);
        else if(opl>mid) query((k<<1)+1,ans,ans_l,ans_r);
        else
        {
            long long lch_max=0,lch_max_r=0,rch_max=0,rch_max_l=0,lch_max_l=0,rch_max_r=0;
            query(k<<1,lch_max,lch_max_l,lch_max_r);
            query((k<<1)+1,rch_max,rch_max_l,rch_max_r);
            ans=max(lch_max,rch_max);
            ans=max(ans,lch_max_r+rch_max_l);
            ans_l=max(lch_max_l,e[k<<1].sum+rch_max_l);
            ans_r=max(rch_max_r,e[(k<<1)+1].sum+lch_max_r);
        }
    }
    void unionn(int k)
    {
        e[k].max=max(max(e[k<<1].max,e[(k<<1)+1].max),e[k<<1].max_r+e[(k<<1)+1].max_l);
        e[k].max_l=max(e[k<<1].max_l,e[k<<1].sum+e[(k<<1)+1].max_l);
        e[k].max_r=max(e[(k<<1)+1].max_r,e[(k<<1)+1].sum+e[k<<1].max_r);
        e[k].sum=e[k<<1].sum+e[(k<<1)+1].sum;
    }
    void build(int k,int l,int r)
    {
        e[k].l=l,e[k].r=r;
        if(l==r) 
        {
            cin>>e[k].max;
            e[k].max_l=e[k].max_r=e[k].sum=e[k].max;
            return;
        }
        int mid=l+r>>1;
        build(k<<1,l,mid);
        build((k<<1)+1,mid+1,r);
        unionn(k);
    }
    int main()
    {
        scanf("%d",&n);
        build(1,1,n);
        scanf("%d",&m);
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&opl,&opr);
            long long ans=0,ans_l=0,ans_r=0;
            query(1,ans,ans_l,ans_r);
            printf("%lld
    ",ans);
        }
    }

    自己做的2个错误:

    1、max_l的更新 : if 左区间的GSS是本身,max_l=max(左区间的max_l,左区间的sum+右区间的max_l)

                             else max_l=左区间的max_l

       错因:例:左区间:5,8,-1,-1   右区间  1,1,1,1  

                     错误方法的GSS=13   正确的GSS=15

    2、在查询时ans,ans_l,ans_r的更新同max,max_l,max_r

        因为max,max_l,max_r更新用到的左区间、右区间信息可以直接拿来用

        而ans,ans_l,ans_r 更新用到的左区间、右区间信息不能直接拿来用,感觉比较棘手,实际只要在递归回溯时更新即可

  • 相关阅读:
    EF--CodeFirst
    一个很吊的文章---框架
    EF的代码优先设计
    MVC3--View层
    asp.net返回值当文件下载问题
    MVC源码
    编译原理
    TPatch动态补丁系统(iOS)
    浅析分布式系统
    如何在腾讯云快速构建一个Wordpress个人站点
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/6360224.html
Copyright © 2011-2022 走看看