zoukankan      html  css  js  c++  java
  • 最大连续和(线段树+分治)

    最大连续和
    Time Limit: 1000 MS Memory Limit: 32768 K
    Total Submit: 61(13 users) Total Accepted: 15(9 users) Rating: Special Judge: No
    Description

    给出一个长度为n的整数序列D,你的任务是对m个询问做出回答。对于询问(a,b),需要找到

    两个下标x和y,使得a<=x<=y<=b,并且Dx+Dx+1+....+Dy尽量大。如果有多组满足条件的x和y,x

    应尽量小。如果还有多解y也应尽量小。

    Input

    第一行是一个整数T,代表测试数据组数。

    对于每组测试数据,第一行为一个整数(1<=n,m<=500000),即整数序列的查询的个数。

    第二行包含n个整数,依次为D1,D2,...Dn的值。这些整数绝对值不超过10^9。以下m行

    每行为一个查询,包含两个整数a和b。

    Output

    对于每组数据,对于每个查询输出一行包含两个整数x和y。

    Sample Input
    1 8 3 -2 3 4 -6 6 10 -7 100 1 8 3 5 6 8
    Sample Output
    2 8 5 5 6 8
    Author
    陈禹@HRBUST

     一开始写出了这样的代码;

    #include<iostream>
    #include<cmath>
    #include<stdio.h>
    #include<algorithm>
    using namespace std;
    typedef long  LONG;
    LONG p[500000];
    struct node
    {
        LONG sum;
        int left,right;
    };
    node check(int i1,int i2)
    {
        node no,max;
        no.sum=0;
        no.left=i1;
        no.right=i1-1;
        //max.sum=-9223372036854775808;
        max.sum=-5000000;
        max.left=i1;
        max.right=i1;
        int i;
        for(i=i1;i<=i2;i++)
        {
            no.sum+=p[i];
            no.right++;
        //    cout<<no.sum<<endl;
            if(no.sum>max.sum)
            {
                max=no;
            //    cout<<max.sum<<endl;
            }
            if(no.sum<0)
            {
                no.left=i+1;
                no.right=i;
                no.sum=0;
            }
        }
        return max;
    }
    int main()
    {
        int T,m,n;
        while(~scanf("%d",&T))
        {
            while(T--)
            {
                int i;
                scanf("%d%d",&n,&m);
                for(i=0;i<n;i++)
                {
                    scanf("%ld",&p[i]);
                }
                int x,y;
                while(m--)
                {
                    scanf("%d%d",&x,&y);
                    node q=check(x-1,y-1);
                    printf("%d %d
    ",q.left+1,q.right+1);
                }
            }
        }
        return 0;
    }

    果断超时
    后来想到线段树:

    写出了代码,中间出了很多错误,基本都是脑残错误

    原理:

    每次需要比较左右子树

    最大值的比较:

    只需要比较三段,(1)max_left,(2)max_right(3)max_left_suffix+max_right_prefix

    以最左边第一个元素为起点的最大值,为什么要更新他,为了使其父亲线段获得最大值

    (1)比较 max_left_prefix与left_all+max_right_prefix

    以最右边最后一个元素开始往左的最大值

    (1)比较max_right_suffix与right_all+max_left_suffix

    #include<cstdio>
    #include<cmath>
    #include<queue>
    #include<iostream>
    using namespace std;
    const int SIZE=500005;
    typedef long  LL;
    struct node
    {
        LL sum,all;
        int pre_r,suf_l;
        int max_l,max_r;
        LL prefixSum,suffixSum;
    } p[SIZE<<2];
    LL a[SIZE];
    
    void pushup(int L,int R,int rt)
    {
        int ll=rt<<1;
        int rr=rt<<1|1;
        p[rt].all=p[ll].all+p[rr].all;
    
        p[rt].prefixSum=p[ll].prefixSum;
        p[rt].pre_r=p[ll].pre_r;
    
        p[rt].suffixSum=p[rr].all+p[ll].suffixSum;
        p[rt].suf_l=p[ll].suf_l;
    
        p[rt].sum=p[ll].sum;
        p[rt].max_l=p[ll].max_l;
        p[rt].max_r=p[ll].max_r;
        if(p[rt].sum<p[rr].sum)
        {
            p[rt].sum=p[rr].sum;
            p[rt].max_l=p[rr].max_l;
            p[rt].max_r=p[rr].max_r;
        }
        if((p[rt].sum<p[ll].suffixSum+p[rr].prefixSum)||
            (p[rt].sum==p[ll].suffixSum+p[rr].prefixSum&&p[rt].max_l>p[ll].suf_l))
        {
            p[rt].sum=p[ll].suffixSum+p[rr].prefixSum;
            p[rt].max_l=p[ll].suf_l;
            p[rt].max_r=p[rr].pre_r;
        }
        if(p[rt].prefixSum<p[ll].all+p[rr].prefixSum)
        {
            p[rt].prefixSum=p[ll].all+p[rr].prefixSum;
            p[rt].pre_r=p[rr].pre_r;
        }
        if(p[rt].suffixSum<p[rr].suffixSum)
        {
            p[rt].suffixSum=p[rr].suffixSum;
            p[rt].suf_l=p[rr].suf_l;
        }
    }
    void build(int L,int R,int rt)
    {
        if(L==R)
        {
            p[rt].all=p[rt].sum=a[L];
            p[rt].prefixSum=a[L];
            p[rt].suffixSum=a[L];
            p[rt].max_l=L;
            p[rt].max_r=L;
            p[rt].pre_r=L;
            p[rt].suf_l=L;
            return ;
        }
        int m=(L+R)>>1;
        int ll=rt<<1;
        int rr=rt<<1|1;
        build(L,m,ll);
        build(m+1,R,rr);
        pushup(L,R,rt);
    }
    node query(int L,int R,int l,int r,int rt)
    {
        if(L==l&&R==r)
        {
            return p[rt];
        }
          /*  if(L==R)   这一段时不可取的,这回大大投稿时间复杂度
           {
                  return p[rt];
            }*/
        int m=(L+R)>>1;
        int ll=rt<<1;
        int rr=rt<<1|1;
        if(m<l)
        {
            return query(m+1,R,l,r,rr);
        }
        if(m>=r)
        {
            return query(L,m,l,r,ll);
        }
        node x=query(L,m,l,m,ll);
        node y=query(m+1,R,m+1,r,rr);
        node z;
        z.all=x.all+y.all;
    
        z.sum=x.sum;
        z.max_l=x.max_l;
        z.max_r=x.max_r;
    
        z.prefixSum=x.prefixSum;
        z.pre_r=x.pre_r;
    
        z.suffixSum=x.suffixSum+y.all;
        z.suf_l=x.suf_l;
        if(z.sum<y.sum)
        {
            z.sum=y.sum;
            z.max_l=y.max_l;
            z.max_r=y.max_r;
        }
        if((z.sum<x.suffixSum+y.prefixSum)||
        (z.sum<x.suffixSum+y.prefixSum&&z.max_l>x.suf_l))
        {
            z.sum=x.suffixSum+y.prefixSum;
            z.max_l=x.suf_l;
            z.max_r=y.pre_r;
        }
        if(z.prefixSum<x.all+y.prefixSum)
        {
            z.prefixSum=x.all+y.prefixSum;
            z.pre_r=y.pre_r;
        }
        if(z.suffixSum<y.suffixSum)
        {
            z.suffixSum=y.suffixSum;
            z.suf_l=y.suf_l;
        }
        return z;
    }
    int main()
    {
        int T;
        while(~scanf("%d",&T))
        {
            while(T--)
            {
                int n,m;
                scanf("%d%d",&n,&m);
                int i;
                for(i=1;i<=n;i++)
                {
                    scanf("%ld",&a[i]);
                }
                build(1,n,1);
                while(m--)
                {
                    int L,R;
                    scanf("%d%d",&L,&R);
                    node q=query(1,n,L,R,1);
                    printf("%d %d
    ",q.max_l,q.max_r);
                }
            }
        }
        return 0;
    }        
  • 相关阅读:
    十天冲刺第1天
    第十四周学习总结
    评价输入法
    第十三周学习总结
    第十二周学习总结
    失物招领平台10
    失物招领平台9
    失物招领平台8
    第十一周学习总结
    失物招领平台7
  • 原文地址:https://www.cnblogs.com/beige1315402725/p/4952459.html
Copyright © 2011-2022 走看看