用三个值来维护最大值,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
*/