UVa 1400(LA 3938)动态最大连续和

【题目链接】
http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=36216

【解题报告】
刘汝佳的《训练指南》里,我觉得这道题目讲的不够详细(并且书上貌似有一点印刷错误?)。

在网上找了很多题解,不过觉得代码写的很丑。直到我看到了这篇题解,觉得代码写的非常漂亮,就虚心学习了。
http://blog.csdn.net/u012997373/article/details/39609271
《UVA - 1400”Ray, Pass me the dishes!”(线段树) 》 –miss_minor

这道题目的算法本身并没有太多困难的令人感到棘手的地方,虽然是普通的线段树单点更新,区间查询,但实现起来,对我来说却非常有困难。原因在于数据的组织能力实在太弱。而这道题又恰恰由繁复的数据及其相应操作组织而成。
对于线段树的每个节点(这本身是一个类)要保存三个线段信息(注意这里又抽象出了一个类:线段),最大前缀,最大后缀,最大子序列。同时还要保存节点相对应的序列左端点和右端点。
对于每条线段,同样要保存左右节点,并且题目中有合并两条线段的操作,还有需要进行线段“优先级”的比较。
因此,如何在有限时间内写出结构清晰,层次完整,便于调试和扩展的代码,是十分考验编码能力的。

【参考代码】

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;

const int maxn=500000+10;
typedef  long  long LL;

int A[maxn];
long long S[maxn];
int n,m;


struct Segment
{
      LL v;
      int l,r;

      Segment (  int l=0, int r=0, LL v=0 )
      {
            this ->l=l;
            this ->r=r;
            this ->v=v;
      }

      Segment operator + (   const Segment& a  )const
      {
            Segment ans;
            ans.l=min(  l,a.l );
            ans.r=max( r,a.r );
            ans.v=v+a.v;
            return ans;
      }

      bool operator < ( const Segment& a )const
      {
            if(    v==a.v  )
            {
                  if(  l==a.l  )
                  {
                        return r>a.r;
                  }
                  return l>a.l;
            }
            return v<a.v;
      }
};


struct node
{
      int l,r;
      Segment max_sub,max_pre,max_suf;
      void set(   int l, int r, Segment max_sub, Segment max_pre, Segment max_suf )
      {
            this->l=l;
            this->r=r;
            this->max_sub=max_sub;
            this->max_pre=max_pre;
            this->max_suf=max_suf;
      }
};

node tree[maxn*4];

void build(    int O, int L, int R )
{
      if(  L>R )return;
      if(  L==R )
      {
            Segment temp(  L,L,A[L]  );
            tree[O].set(    L,R,temp,temp,temp );
            return ;
      }
      int mid=L+(R-L)/2;
      build(  O*2,   L, mid );
      build( O*2+1, mid+1,R );

      Segment now_left(   L,mid,S[mid]-S[L-1]  );
      Segment now_right(  mid+1, R, S[R]-S[mid] );

      tree[O].max_sub=max(       tree[O*2].max_suf+tree[O*2+1].max_pre    ,   max(tree[O*2].max_sub , tree[O*2+1].max_sub)          );
      tree[O].max_pre=max(    tree[O*2].max_pre ,    now_left+tree[O*2+1].max_pre  );
      tree[O].max_suf=max(   tree[O*2+1].max_suf,  now_right+tree[O*2].max_suf );
      tree[O].l=tree[O*2].l;
      tree[O].r=tree[O*2+1].r;
}


node query(   int O, int qL, int qR  )
{
      int L=tree[O].l,R=tree[O].r;
      int mid=(L+R)/2;

   //   cout<<L<<"  "<<R<<endl;

      if(     qL<=L && R<=qR  ) return tree[O];
      if(  qR<=mid  )return query(   O*2, qL, qR   );
            else if(     qL>mid  ) return query(  O*2+1,  qL, qR    );
                  else  //if(   qR>=L &&  qL<=R  )
                  {
                        node nL=query(  O*2, qL,qR );
                        node nR=query(  O*2+1,  qL, qR );
                        node ret;
                        LL S_L=S[nL.r] - S[nL.l-1],   S_R=S[nR.r]-S[nR.l-1];
                        Segment L_seg(   L,mid,S_L  );
                        Segment R_seg(  mid+1, R, S_R );
                        ret.max_pre=max(       nL.max_pre,   L_seg+nR.max_pre    );
                        ret.max_sub=max(      max(  nL.max_sub,nR.max_sub ),  nL.max_suf+nR.max_pre    );
                        ret.max_suf=max(    nR.max_suf, R_seg+nL.max_suf  );
                        ret.l=nL.l; ret.r=nR.r;
                        return ret;
                  }
}


int main(   )
{
      int kase=0;
      while(~scanf(   "%d%d", &n, &m ))
      {
            printf(  "Case %d:\n",++kase );
            for(  int i=1; i<=n; i++ )
            {
                  scanf(  "%d",&A[i] );
                  S[i]=S[i-1]+A[i];
            }
            build(  1, 1, n );
            for(   int i=1; i<=m; i++ )
            {
                  int  qL, qR;
                  scanf("%d%d",&qL,&qR);
                  node ans=query(   1, qL, qR );
                  printf(  "%d %d\n", ans.max_sub.l, ans.max_sub.r );
               //   cout<<tree[1].max_sub.l<<"  "<<tree[4].max_sub.r<<endl;

            }

      }



      return 0 ;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值