很经典的线段树维护最大子段和
我们只需要维护一下每一个区间的最大前缀,后缀,子段和区间和
对于每一个区间
他的最大前缀可能是左儿子的最大前缀或者左儿子的和加上右儿子最大前缀
后缀,同理
最大子段可能是左儿子最大后缀加上右儿子最大前缀或者说左,右儿子的最大子段
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int n,m;
int k;
int a,b;
int x;
struct tree{
int lm;
int rm;
int mx;
int sum;
}tr[2000008];
tree pushup(tree x,tree y){
tree ans;
ans.sum=x.sum+y.sum;
ans.lm=max(x.lm,x.sum+y.lm);
ans.rm=max(y.rm,y.sum+x.rm);
ans.mx=max(x.mx,max(y.mx,x.rm+y.lm));
return ans;
}
void add(int ro,int l,int r,int L,int R,int key){
if(l==r){
tr[ro].lm=tr[ro].mx=tr[ro].rm=tr[ro].sum=key;
return ;
}
int mid=(l+r)>>1;
if(L<=mid) add(ro<<1,l,mid,L,R,key);
if(R>mid) add(ro<<1|1,mid+1,r,L,R,key);
tr[ro]=pushup(tr[ro<<1],tr[ro<<1|1]);
}
tree query(int ro,int l,int r,int L,int R){
if(L<=l&&r<=R){
return tr[ro];
}
int mid=(l+r)>>1;
if(mid<R&&L<=mid){
return pushup(query(ro<<1,l,mid,L,R),query(ro<<1|1,mid+1,r,L,R));
}else
if(mid>=R){
return query(ro<<1,l,mid,L,R);
} else if(mid<L){
return query(ro<<1|1,mid+1,r,L,R);
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i){
scanf("%d",&x);
add(1,1,n,i,i,x);
// cout<<query(1,1,n,2,3).mx<<endl;
}
for(int i=1;i<=m;++i){
scanf("%d%d%d",&k,&a,&b);
if(k==1){
if(a>b)
swap(a,b);
cout<<query(1,1,n,a,b).mx<<endl;
}else{
add(1,1,n,a,a,b);
}
}
return 0;
}