题目
单点修改+区间查找最大连续子段和
分析
这道题可以用线段树解决,
维护四个数,总和,左边的最大值,右边的最大值及答案
tree[k].sum=tree[k<<1].sum+tree[k<<1|1].sum;//显而易见,左边+右边
tree[k].lmax=max(tree[k<<1].lmax,tree[k<<1].sum+tree[k<<1|1].lmax);//最大值=max(左边的最大值,左边的总和+右边的最大值)
tree[k].rmax=max(tree[k<<1|1].rmax,tree[k<<1|1].sum+tree[k<<1].rmax);//the same
tree[k].w=max(max(tree[k<<1].w,tree[k<<1|1].w),tree[k<<1].rmax+tree[k<<1|1].lmax);//那么答案可以是左边,右边的答案,也可以是中间的部分
代码
#include <cstdio>
struct node{int sum,lmax,rmax,w;}tree[2000001];
int n,m,a[500001];
int in(){
int f=1,ans=0; char c=getchar();
while ((c<48||c>57)&&c!='-') c=getchar();
if (c=='-') f=-f,c=getchar();
while (c>47&&c<58) ans=ans*10+c-48,c=getchar();
return ans*f;
}
int max(int a,int b){return (a>b)?a:b;}
void calc(int k){
tree[k].sum=tree[k<<1].sum+tree[k<<1|1].sum;
tree[k].lmax=max(tree[k<<1].lmax,tree[k<<1].sum+tree[k<<1|1].lmax);
tree[k].rmax=max(tree[k<<1|1].rmax,tree[k<<1|1].sum+tree[k<<1].rmax);
tree[k].w=max(max(tree[k<<1].w,tree[k<<1|1].w),tree[k<<1].rmax+tree[k<<1|1].lmax);
}
void build(int k,int l,int r){
if (l==r) {tree[k]=(node){a[l],a[l],a[l],a[l]}; return;}
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
calc(k);
}
node ask(int k,int l,int r,int x,int y){
if (l==x&&r==y) return tree[k];
int mid=(l+r)>>1;
if (y<=mid) return ask(k<<1,l,mid,x,y);
else if (x>mid) return ask(k<<1|1,mid+1,r,x,y);
else{
node a=ask(k<<1,l,mid,x,mid);
node b=ask(k<<1|1,mid+1,r,mid+1,y);
node c;
c.sum=a.sum+b.sum;
c.lmax=max(a.lmax,a.sum+b.lmax);
c.rmax=max(b.rmax,b.sum+a.rmax);
c.w=max(max(a.w,b.w),a.rmax+b.lmax);
return c;//找到答案
}
}
void change(int k,int l,int r,int x,int y){
if (l==r) {tree[k]=(node){y,y,y,y}; return;}//单点修改
int mid=(l+r)>>1;
if (x<=mid) change(k<<1,l,mid,x,y); else change(k<<1|1,mid+1,r,x,y);
calc(k);//同时维护父节点
}
int main(){
n=in(); m=in();
for (register int i=1;i<=n;i++) a[i]=in();
build(1,1,n);
while (m--){
int q=in(); int x=in(); int y=in();
if (q==1){
if (x>y) x^=y,y^=x,x^=y;//特判
printf("%d\n",ask(1,1,n,x,y).w);
}
else change(1,1,n,x,y);
}
return 0;
}