给定长度为N的数列A,以及M条指令,每条指令可能是以下两种之一:
1、“1 x y”,查询区间 [x,y] 中的最大连续子段和,即 maxx≤l≤r≤y{∑ri=lA[i]}。
2、“2 x y”,把 A[x] 改成 y。
对于每个查询指令,输出一个整数表示答案。
输入格式
第一行两个整数N,M。
第二行N个整数A[i]。
接下来M行每行3个整数k,x,y,k=1表示查询(此时如果x>y,请交换x,y),k=2表示修改。
输出格式
对于每个查询指令输出一个整数表示答案。
每个答案占一行。
数据范围
N≤500000,M≤100000
输入样例:
5 3
1 2 -3 4 5
1 2 3
2 2 -1
1 3 2
输出样例:
2
-1
思路:用线段树维护区间和的同时增加lmax和rmax变量维护区间最大前缀子段和以及区间最大后缀子段和,然后利用这些信息的关系可以维护区间最大连续子段和maxsum,每个连续子段都可以通过左区间和,右区间和和lmax,rmax相结合的部分构造出来:
区间前缀的最大连续子段和=max(左子区间和+右子区间的前缀的的最大连续子段)
区间后缀的最大连续子段和=max(右子区间和+左子区间的后缀的的最大连续子段)
用maxsum维护这些信息的max值即可,即:
区间最大连续子段和=最大的(左子区间的后缀最大子段和+右子区间前缀的最大子段和)
完整代码:
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxn=5e5+5,inf=0x3f3f3f3f;
struct tree
{
int l,r,lmax,rmax,sum,maxsum;
}tr[maxn<<2];
int n,m,a[maxn];
void pushup(int p)//回溯时,通过子结点信息维护父结点信息
{
tr[p].sum=tr[p<<1].sum+tr[p<<1|1].sum;//父结点区间和等于其左右子区间和的和
tr[p].lmax=max(tr[p<<1].lmax,tr[p<<1].sum+tr[p<<1|1].lmax);//区间前缀的最大连续子段和=所有左子区间和和右子区间的前缀的的最大连续子段和构造出来的所有子段和的最大值
tr[p].rmax=max(tr[p<<1|1].rmax,tr[p<<1|1].sum+tr[p<<1].rmax);//区间后缀的最大连续子段和=所有右子区间和和左子区间的后缀的的最大连续子段和构造出来的所有子段和的最大值
tr[p].maxsum=max(max(tr[p<<1].maxsum,tr[p<<1|1].maxsum),tr[p<<1].rmax+tr[p<<1|1].lmax);
}
void build(int p,int l,int r)
{
tr[p].l=l;
tr[p].r=r;
if(l==r){
tr[p]={l,r,a[l],a[l],a[l],a[l]};
return;
}
int mid=l+r>>1;
build(p<<1,l,mid);
build(p<<1|1,mid+1,r);
pushup(p);
}
void update(int p,int k,int v)
{
if(tr[p].l==tr[p].r){
tr[p].sum=v;
tr[p].lmax=v;
tr[p].rmax=v;
tr[p].maxsum=v;
return;
}
int mid=tr[p].l+tr[p].r>>1;
if(k<=mid) update(p<<1,k,v);
else update(p<<1|1,k,v);
pushup(p);
}
tree query(int p,int l,int r)
{
if(tr[p].l>=l&&tr[p].r<=r){
return tr[p];
}
int mid=tr[p].l+tr[p].r>>1;
tree a,b,c;
a.sum=b.sum=-inf;
a.lmax=b.lmax=-inf;
a.rmax=b.rmax=-inf;
a.maxsum=b.maxsum=-inf;
c.sum=0;
if(l<=mid){
a=query(p<<1,l,r);
c.sum+=a.sum;
}
if(r>mid){
b=query(p<<1|1,l,r);
c.sum+=b.sum;
}
c.maxsum=max(max(a.maxsum,b.maxsum),a.rmax+b.lmax);
c.lmax=max(a.lmax,a.sum+b.lmax);
if(l>mid){
c.lmax=max(c.lmax,b.lmax);
}
c.rmax=max(b.rmax,b.sum+a.rmax);
if(r<=mid){
c.rmax=max(c.rmax,a.rmax);
}
return c;
}
int main()
{
ios::sync_with_stdio();
cin.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i];
build(1,1,n);
while(m--){
int op,u,v;
cin>>op>>u>>v;
if(op==1){
if(u>v) swap(u,v);
cout<<query(1,u,v).maxsum<<endl;
}
else{
update(1,u,v);
}
}
return 0;
}