传送门
用线段树维护区间最大前缀后缀,区间最优解和区间和。
合并时候xjb乱搞以下就可以了。
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 500010
using namespace std;
int a[N],n,m,fl,x,y;
struct node{int mx,lmx,rmx,sum;}t[N*4];
node merge(node a,node b){
node tmp;
tmp.lmx=max(a.lmx,a.sum+b.lmx);
tmp.rmx=max(b.rmx,b.sum+a.rmx);
tmp.mx=max(a.rmx+b.lmx,max(a.mx,b.mx));
tmp.sum=a.sum+b.sum;
return tmp;
}
void build(int k,int l,int r){
if (l==r){
t[k].mx=t[k].lmx=t[k].rmx=t[k].sum=a[l];
return;
}
int mid=(l+r)/2;
build(k*2,l,mid);
build(k*2+1,mid+1,r);
t[k]=merge(t[k*2],t[k*2+1]);
}
void change(int k,int l,int r,int x,int v){
if (l==r){
t[k].mx=t[k].lmx=t[k].rmx=t[k].sum=v;
return;
}
int mid=(l+r)/2;
if (x<=mid) change(k*2,l,mid,x,v);
else change(k*2+1,mid+1,r,x,v);
t[k]=merge(t[k*2],t[k*2+1]);
}
node ask(int k,int l,int r,int x,int y){
if (l==x&&r==y) return t[k];
int mid=(l+r)/2;
if (y<=mid) return ask(k*2,l,mid,x,y);
if (x>mid) return ask(k*2+1,mid+1,r,x,y);
return merge(ask(k*2,l,mid,x,mid),ask(k*2+1,mid+1,r,mid+1,y));
}
int main(){
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
build(1,1,n);
for (int i=1;i<=m;i++){
scanf("%d%d%d",&fl,&x,&y);
if (fl==1){
if (x>y) swap(x,y);
printf("%d\n",ask(1,1,n,x,y).mx);
}
else change(1,1,n,x,y);
}
}