题意:n个数的序列,m个询问,每次询问[i,j]内最大的子段和的区间。
思路:设一个区间起点为左边界的最大子段和为lsum,终点为右边界的最大子段和为rsum,整个区间和为sum。
区间[i,j]可以分成[i,mid],[mid+1,j],则[i,j]的最大子段和即为max([i,mid]的最大子段和,[mid+1,j]的最大子段和,[i,mid]的rsum+[mid+1,j]的lsum)。
那么[i,j]的lsum则为max([i,mid]的lsum,[i,mid]的sum+[mid+1,j]的lsum)。
[i,j]的rsum则为max([mid+1,j]的rsum,[mid+1,j]的sum+[i,mid]的rsum)。
#include<stdio.h>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<stdlib.h>
using namespace std;
#define p -500000000000001
#define NUM 510000
#define ll long long
int n,m;
ll a[NUM];
struct ANS
{
int st,en;
ll sum;
bool operator<(const ANS& x)const
{
if(sum!=x.sum)
return sum<x.sum;
if(st!=x.st)
return st>x.st;
return en>x.en;
}
ANS operator+(const ANS& x)const//合并两个子段和
{
ANS y;
y.st=min(x.st,st);
y.en=max(x.en,en);
y.sum=x.sum+sum;
return y;
}
};
struct T
{
int r,l,mid;
ANS lw,rw,w,tsum;
}t[3*NUM];
void build(int x,int l,int r)
{
t[x].l=l;
t[x].r=r;
t[x].mid=(l+r)>>1;
if(l==r)
{
t[x].lw.st=t[x].lw.en=l;
t[x].lw.sum=a[l];
t[x].tsum=t[x].w=t[x].rw=t[x].lw;
return ;
}
build(x<<1,l,t[x].mid);
build(x<<1|1,t[x].mid+1,r);
t[x].tsum=t[x<<1].tsum+t[x<<1|1].tsum;
t[x].rw=max(t[x<<1|1].rw,t[x<<1].rw+t[x<<1|1].tsum);
t[x].lw=max(t[x<<1].lw,t[x<<1|1].lw+t[x<<1].tsum);
t[x].w=t[x<<1].rw+t[x<<1|1].lw;
t[x].w=max(t[x].w,t[x<<1].w);
t[x].w=max(t[x].w,t[x<<1|1].w);
}
ANS get(int x,int l,int r)//求整个区间和
{
if(t[x].l==l&&t[x].r==r)
return t[x].tsum;
if(t[x].mid<l)
return get(x<<1|1,l,r);
if(t[x].mid>=r)
return get(x<<1,l,r);
return get(x<<1,l,t[x].mid)+get(x<<1|1,t[x].mid+1,r);
}
ANS solvel(int x,int l,int r)//求起点为l的最大子段和
{
if(t[x].l==l&&t[x].lw.en<=r)
return t[x].lw;
if(t[x].mid<l)
return solvel(x<<1|1,l,r);
if(t[x].mid>=r)
return solvel(x<<1,l,r);
return max(get(x<<1,l,t[x].mid)+solvel(x<<1|1,t[x].mid+1,r),solvel(x<<1,l,t[x].mid));
}
ANS solver(int x,int l,int r)//求终点为r的最大子段和
{
if(t[x].r==r&&t[x].rw.st>=l)
return t[x].rw;
if(t[x].mid<l)
return solver(x<<1|1,l,r);
if(t[x].mid>=r)
return solver(x<<1,l,r);
return max(get(x<<1|1,t[x].mid+1,r)+solver(x<<1,l,t[x].mid),solver(x<<1|1,t[x].mid+1,r));
}
ANS solve(int x,int l,int r)//求区间[l,r]的最大子段和
{
if(t[x].w.st>=l&&t[x].w.en<=r)
return t[x].w;
if(t[x].mid<l)
return solve(x<<1|1,l,r);
if(t[x].mid>=r)
return solve(x<<1,l,r);
ANS ans=max(solve(x<<1,l,t[x].mid),solve(x<<1|1,t[x].mid+1,r));
ans=max(ans,solver(x<<1,l,t[x].mid)+solvel(x<<1|1,t[x].mid+1,r));
return ans;
}
int main()
{
int l,r;
int t=0;
ANS x;
while(scanf("%d%d",&n,&m)!=EOF)
{
++t;
for(int i=1;i<=n;++i)
scanf("%lld",&a[i]);
build(1,1,n);
printf("Case %d:\n",t);
while(m--)
{
scanf("%d%d",&l,&r);
x=solve(1,l,r);
printf("%d %d\n",x.st,x.en);
}
}
}