题解 SP1716 【GSS3 - Can you answer these queries III】
若
题解:
我们需要维护区间的最大子段和。
对于维护这种类型的数据,比较常用的就是线段树。
设区间
我们称区间内达到最大子段和的子段为最大子段。
将区间
-
完全包含于
L=(l,mid) ; -
完全包含于
R=(mid+1,r) ; -
区间
L 的后一段与区间R 的前一段。
若为前两种,可将
若为最后一种,我们需要左区间的后缀和与右区间的前缀和最大。不难发现,取到最大值时,必定是区间
设区间的最大前缀和
在这些表示下,我们就能维护最大子段和了
但是我们还要维护
对于区间
-
-
整个
L 再加上R 的最大前缀和。
设区间和
同理,对于区间
-
-
整个
R 再加上L 的最大后缀和。
即
最后还剩一个
回顾一下我们的维护方式:
于是可以用线段树
代码中用结构体写的线段树。详见代码。
#include<bits/stdc++.h>
using namespace std;
const int maxn=50000+233;
int n,q,a[maxn];
struct Seg{
int l,r,sum; //区间左右端点,区间和
int data,pre,suf; //最大子段和,最大前缀和,最大后缀和
}tree[maxn*4];
void pushup(int pos){ //RT的维护
tree[pos].sum=tree[pos*2].sum+tree[pos*2+1].sum;
tree[pos].data=max(tree[pos*2].data,tree[pos*2+1].data);
tree[pos].data=max(tree[pos].data,tree[pos*2].suf+tree[pos*2+1].pre);
tree[pos].pre=max(tree[pos*2].pre,tree[pos*2].sum+tree[pos*2+1].pre);
tree[pos].suf=max(tree[pos*2+1].suf,tree[pos*2].suf+tree[pos*2+1].sum);
}
void biuld(int pos,int l,int r){ //标准建树
if(l==r){
tree[pos].l=tree[pos].r=l;
tree[pos].data=tree[pos].pre=tree[pos].suf=tree[pos].sum=a[l];
return;
}
int mid=(l+r)/2;
biuld(pos*2,l,mid);
biuld(pos*2+1,mid+1,r);
tree[pos].l=tree[pos*2].l;
tree[pos].r=tree[pos*2+1].r;
pushup(pos);
}
void update(int pos,int x,int y){ //标准upd
if(tree[pos].l==tree[pos].r){
tree[pos].data=tree[pos].pre=tree[pos].suf=tree[pos].sum=y;
return;
}
int mid=(tree[pos].l+tree[pos].r)/2;
if(x<=mid)update(pos*2,x,y);
else update(pos*2+1,x,y);
pushup(pos);
}
Seg query(int pos,int l,int r){
if(l<=tree[pos].l&&tree[pos].r<=r)return tree[pos];
int mid=(tree[pos].l+tree[pos].r)/2;
if(l<=mid&&r>mid){ //将(l,r)拆分成(l,mid)U(mid+1,r)
Seg resl=query(pos*2,l,r);
Seg resr=query(pos*2+1,l,r);
Seg res;
res.sum=resl.sum+resr.sum;
res.data=max(resl.data,resr.data);
res.data=max(res.data,resl.suf+resr.pre);
res.pre=max(resl.pre,resl.sum+resr.pre);
res.suf=max(resr.suf,resr.sum+resl.suf);
return res;
}
else{ //若(l,r)没有完全包含pos所在区间,直接递归
if(l<=mid)return query(pos*2,l,r);
if(r>mid)return query(pos*2+1,l,r);
}
}
int main(){
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
biuld(1,1,n);
cin>>q;
for(int i=1;i<=q;i++){
int opt,l,r;
cin>>opt>>l>>r;
if(opt)cout<<query(1,l,r).data<<endl;
else update(1,l,r);
}
return 0;
}