<h2>题目描述</h2>
给定一个长度为 $n$ 的序列 $a$,有 $q$ 个询问,询问有两种:
- 单点修改</p>
- <p>给定一组 $L,R$,求 $$max{\Sigma_{i=l}^{r}a_i}(L\leq l \leq r \leq R)$$</p>
<p>其中 $n,q \leq 50000$。
<h2>解题报告</h2>
这个有和,我们可以用线段树维护。
线段树需要维护四个值:当前区间的前缀最大值,当前区间的后缀最大值,当前区间的答案,以及区间和。
这些显然可以通过线段树合并来实现。
前缀最大值 = max(左儿子的前缀最大值,左儿子的和 + 右儿子的前缀最大值)
后缀最大值 = max(右儿子的后缀最大值,右儿子的和 + 左儿子的后缀最大值)
答案 = max(左儿子的答案,右儿子的答案,左儿子的后缀最大值 + 右儿子的前缀最大值)
也就是考虑相交和不相交的部分然后合并了。
具体见代码。
<h3>代码</h3>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <climits>
#include <cstdio>
#include <vector>
#include <cstdlib>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#define Re register
#define LL long long
#define U unsigned
#define FOR(i,a,b) for(Re int i = a;i <= b;++i)
#define RFOR(i,a,b) for(Re int i = a;i >= b;--i)
#define SFOR(i,a,b,c) for(Re int i = a;i <= b;i+=c)
#define CLR(i,a) memset(i,a,sizeof(i))
#define BR printf("--------------------n")
#define DEBUG(x) std::cerr << #x << '=' << x << std::endl
namespace fastIO{
#define BUF_SIZE 100000
#define OUT_SIZE 100000
#define ll long long
bool IOerror=0;
inline char nc(){
static char buf[BUF_SIZE],p1=buf+BUF_SIZE,pend=buf+BUF_SIZE;
if (p1==pend){
p1=buf; pend=buf+fread(buf,1,BUF_SIZE,stdin);
if (pend==p1){IOerror=1;return -1;}
}
return *p1++;
}
inline bool blank(char ch){return ch==' '||ch=='n'||ch=='r'||ch=='t';}
inline void read(int &x){
bool sign=0; char ch=nc(); x=0;
for (;blank(ch);ch=nc());
if (IOerror)return;
if (ch=='-')sign=1,ch=nc();
for (;ch>='0'&&ch<='9';ch=nc())x=x*10+ch-'0';
if (sign)x=-x;
}
inline void read(ll &x){
bool sign=0; char ch=nc(); x=0;
for (;blank(ch);ch=nc());
if (IOerror)return;
if (ch=='-')sign=1,ch=nc();
for (;ch>='0'&&ch<='9';ch=nc())x=x*10+ch-'0';
if (sign)x=-x;
}
#undef ll
#undef OUT_SIZE
#undef BUF_SIZE
};
using namespace fastIO;
const int MAXN = 50000 + 5;
struct SegmentTree New(int ,int ,SegmentTree ,SegmentTree *);
struct SegmentTree{
int l,r;
LL lmax,rmax,mmax,sum; //前缀 max,后缀 max,跨越终点 max,和。
SegmentTree lc,rc;
static SegmentTree *build(int l,int r){
int mid = (l + r) >> 1;
return (l == r) ? New(l,r,NULL,NULL) : New(l,r,build(l,mid),build(mid+1,r));
}
inline void pushup(){
sum = lc->sum + rc->sum;
lmax = std::max(lc->lmax,lc->sum + rc->lmax);
rmax = std::max(rc->rmax,lc->rmax + rc->sum);
mmax = std::max(std::max(lc->mmax,rc->mmax),lc->rmax + rc->lmax);
}
inline void update(int pos,int x){
if(l == r){
lmax = rmax = mmax = sum = x;
return;
}
int mid = (l + r) >> 1;
if(pos <= mid) lc->update(pos,x);
else rc->update(pos,x);
pushup();
}
inline SegmentTree query(int L,int R){
if(L == l && R == r)
return (SegmentTree){0,0,lmax,rmax,mmax,sum,NULL,NULL};
int mid = (l + r) >> 1;
if(R <= mid) return lc->query(L,R);
if(L > mid) return rc->query(L,R);
SegmentTree lans = lc->query(L,mid),rans = rc->query(mid + 1,R),ans;
ans.lmax = std::max(lans.lmax,lans.sum + rans.lmax);
ans.rmax = std::max(rans.rmax,rans.sum + lans.rmax);
ans.sum = lans.sum + rans.sum;
ans.mmax = std::max(std::max(lans.mmax,rans.mmax),lans.rmax + rans.lmax);
return ans;
}
}pool[MAXN<<2],frog = pool,segt;
SegmentTree New(int l,int r,SegmentTree lc,SegmentTree *rc){
SegmentTree *ret = ++frog;
ret->l = l;ret->r = r;
ret->lc = lc;ret->rc = rc;
ret->lmax = ret->rmax = ret->mmax = INT_MIN;
return ret;
}
int N,M;
int opt,x,y;
SegmentTree ans;
int main(){
read(N);
segt = SegmentTree::build(1,N);
FOR(i,1,N){
int x;
read(x);
segt->update(i,x);
}
read(M);
while(M--){
read(opt);read(x);read(y);
if(opt){
printf("%lldn",segt->query(x,y).mmax);
}
else{
segt->update(x,y);
}
}
return 0;
}