题目描述

给出了序列\(A[1],A[2],…,A[N]。 (a[i]≤15007,1≤N≤50000)\)。查询定义如下: 查询\((x,y)=max{a[i]+a[i+1]+...+a[j];x≤i≤j≤y}\)。 给定\(M\)个查询,程序必须输出这些查询的结果。

输入输出格式

输入格式:

  • 输入文件的第一行包含整数\(N\)
  • 在第二行,\(N\)个数字跟随。
  • 第三行包含整数\(M\)
  • \(M\)行跟在后面,其中第\(1\)行包含两个数字\(x_i\)\(y_i\)

输出格式:

您的程序应该输出\(M\)查询的结果,每一行一个查询。

输入输出样例

输入样例#1:

3 
-1 2 3
1
1 2

输出样例#1:

2

思路:一道线段树维护区间最大字段和的裸题,就是分三种情况讨论,完全在左子树,完全在右子树,或在左右子树之间。

代码:

#include<cstdio>
#include<algorithm>
#include<cctype>
#define maxn 50007
#define ls rt<<1
#define rs rt<<1|1
using namespace std;
inline int qread() {
  char c=getchar();int num=0,f=1;
  for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
  for(;isdigit(c);c=getchar()) num=num*10+c-'0';
  return num*f;
}
int n,m;
struct Tree {
  int lmax,rmax,sum,maxx;
}tree[maxn<<2];
inline void pushup(int rt) {
  tree[rt].lmax=max(tree[ls].lmax,tree[ls].sum+tree[rs].lmax);
  tree[rt].rmax=max(tree[rs].rmax,tree[rs].sum+tree[ls].rmax);
  tree[rt].maxx=max(tree[ls].rmax+tree[rs].lmax,max(tree[ls].maxx,tree[rs].maxx));
  tree[rt].sum=tree[ls].sum+tree[rs].sum;
}
void build(int rt, int l, int r) {
  if(l==r) {
    tree[rt].lmax=tree[rt].rmax=tree[rt].sum=tree[rt].maxx=qread();
    return;
  }
  int mid=(l+r)>>1;
  build(ls,l,mid);
  build(rs,mid+1,r);
  pushup(rt);
}
Tree query(int rt, int l, int r, int L, int R) {
  if(L==l&&r==R) return tree[rt];
  int mid=(l+r)>>1;
  if(L>mid) return query(rs,mid+1,r,L,R);
  else if(R<=mid) return query(ls,l,mid,L,R);
  else {
    Tree a=query(ls,l,mid,L,mid),b=query(rs,mid+1,r,mid+1,R),c;
    c.lmax=max(a.lmax,a.sum+b.lmax);
    c.rmax=max(b.rmax,b.sum+a.rmax);
    c.sum=a.sum+b.sum;
    c.maxx=max(a.rmax+b.lmax,max(a.maxx,b.maxx));
    return c;
  }
}
int main() {
  n=qread();
  build(1,1,n);
  m=qread();
  for(int i=1,x,y;i<=m;++i) {
    x=qread(),y=qread();
    printf("%d\n",query(1,1,n,x,y).maxx);
  }
  return 0;
}