UVA - 1400(区间连续最大和)

用三个值来维护最大值,pre_max,suf_max,max;

分别代表区间的前缀最大和,后缀最大和,和连续最大和。则 每个线段都维护三个值,边可以合并。

注意为了求出所要求的区间最优区间l,r还要 维护当前最优l,r和前缀最大和最优位置prep,后缀最大和最优位置sufp,且维护时尽量选靠左的点;

这里的向上push_up和要查区间的合并,其实都是对两个线段的合并,先一个函数就可以了。

#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define rep(i,n) for(int (i)=0;(i)<(n);i++)
#define Rep(i,n) for(int (i)=1;(i)<=(n);i++)

const int N = 511111;
struct node{
  LL sub,pre,suf,sum;
  LL l,r,prep,sufp;
  node(LL x=0,LL y=0,LL z=0):
      sub(x),l(y),r(z){}
}a[N<<2];
LL b[N];
node get(node a,node b){
  if(a.sub !=b.sub){
     return (a.sub > b.sub ? a:b);
  }
  if(a.l != b.l)
    return (a.l < b.l ? a : b);
  return (a.r < b.r ? a : b);
}
node better(node a,node b){
  node te ,tl= get(a,b);
   tl = get(tl,node(a.suf+b.pre,a.sufp,b.prep));
  te.l = tl.l; te.r = tl.r;
  te.sub = max(a.sub,b.sub);
  te.sub = max(te.sub,a.suf+b.pre);
  te.suf = max(b.suf,b.sum+a.suf);
  te.sufp = (b.suf > b.sum+a.suf ? b.sufp:a.sufp);
  te.pre = max(a.pre,a.sum+b.pre);
  te.prep = (a.pre >= a.sum+b.pre ? a.prep:b.prep);
  te.sum = a.sum+b.sum;
  return te;
}
void push_up(int l,int r,int rt){
  a[rt] = better(a[rt<<1],a[rt<<1|1]);
}
void build(int l,int r,int rt){
   if(l==r){
     a[rt].pre = a[rt].suf = a[rt].sum =a[rt].sub = b[l];
     a[rt].l = l; a[rt].r = r; a[rt].prep = a[rt].sufp =l;
     return ;
   }
   int m = (l+r)>>1;
   build(lson);
   build(rson);
   push_up(l,r,rt);
}
node query(int l,int r,int rt,int L,int R){
  if(L<=l&&r<=R){
     return a[rt];
  }
  int m =(l+r)>>1,ok=0;
  node res;
  if(L<=m){ok = 1; res=query(lson,L,R);}
  if(R>m){
     if(ok) res = better(res,query(rson,L,R));
     else res = query(rson,L,R);
  }
  return res;
}
int n,M;
int main()
{
    int kase = 1;
    while(scanf("%d %d",&n,&M)==2){
       for(int i=1;i<=n;i++){
         scanf("%lld",&b[i]);
       }
       build(1,n,1);
       printf("Case %d:\n",kase++);
       while(M--){
          int x,y;
         scanf("%d %d",&x,&y);
         node res = query(1,n,1,x,y);
         printf("%lld %lld\n",res.l,res.r);
       }
    }
    return 0;
}
/*
3 3
2147483647 2147483647 1
1 3
*/



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值