题目链接如下所示:
线段树和DP的结合。
首先,关于DP,对于一个区间[a,b],我们维护最大序列和max_sum,相应最小序列和min_sum,维护以a开头的最大最小序列和lmax,lmin,相应以b结尾的最大最小序列和为rmax,rmin,同样记录一个sum来表示区间总和。在push_up的时候我们自底向上更新序列和:
1.对于max_sum,我们对当前节点左右孩子最大的区间和,以及左孩子的rmax和右孩子的lmax之和三者取其最大。min_sum类似。
2.对于lmax,我们对当前节点的左孩子的lmax,左孩子的sum和有孩子的lmax之和作比较,取两者最大的一个。其余类似。
3.sum当然要一直累加。
接下来就是在建树和update的时候更新push_up即可。
代码如下所示:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<ctime>
#include<vector>
#include<algorithm>
#include<cstring>
#include<set>
#include<map>
#include<queue>
#include<string>
#include<cmath>
#include<climits>
using namespace std;
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
const int MAXN=100005;
int sum[MAXN<<2],max_sum[MAXN<<2],min_sum[MAXN<<2];
int lmax[MAXN<<2],rmax[MAXN<<2];
int lmin[MAXN<<2],rmin[MAXN<<2];
int a[MAXN];
void push_up(int rt){
int l=rt<<1;
int r=rt<<1|1;
sum[rt]=sum[l]+sum[r];
max_sum[rt]= max(max(max_sum[l],max_sum[r]),rmax[l]+lmax[r]);
min_sum[rt]= min(min(min_sum[l],min_sum[r]),rmin[l]+lmin[r]);
lmax[rt]= max(lmax[l],sum[l]+lmax[r]);
rmax[rt]= max(rmax[r],sum[r]+rmax[l]);
lmin[rt]= min(lmin[l],sum[l]+lmin[r]);
rmin[rt]= min(rmin[r],sum[r]+rmin[l]);
}
void build(int l,int r,int rt){
if (l==r){
max_sum[rt]=min_sum[rt]=a[l];
lmax[rt]=rmax[rt]=lmin[rt]=rmin[rt]=a[l];
sum[rt]=a[l];
return;
}
int mid=(l+r)>>1;
build(lson);
build(rson);
push_up(rt);
}
void update(int pos,int val,int l,int r,int rt){
if (l==r){
max_sum[rt]=min_sum[rt]=val;
lmax[rt]=rmax[rt]=lmin[rt]=rmin[rt]=val;
sum[rt]=val;
return;
}
int mid=(l+r)>>1;
if (pos<=mid){
update(pos,val,lson);
} else{
update(pos,val,rson);
}
push_up(rt);
}
int main(){
int n,m;
int pos,val,ans;
scanf("%d",&n);
for (int i = 1; i <= n; ++i) {
scanf("%d",&a[i]);
}
build(1,n,1);
scanf("%d",&m);
while (m--){
scanf("%d %d",&pos,&val);
update(pos,val,1,n,1);
if (sum[1]==max_sum[1]){
ans=sum[1]-min_sum[1];
}else{
ans=max(sum[1]-min_sum[1],max_sum[1]);
}
printf("%d\n",ans);
}
return 0;
}