题意:线段树单点修改、区间连续最大值查询。(区间内有负数、正数)
思路:在这里我们需要维护四个值(emmm 这是个模板题,为啥维护四个值,模板就这样我也没办法啊)。lmax、rmax、mmax、sum。含义分别是:左边开始的连续最大值,右边开始的最大值,中间某段的连续最大值和该区间值的总和。
注意核心代码是query代码 updata就是正常的维护即可,要注意的是,当一个点被修改,上述每个值都要被修改。大胆改就完了,反正有pushup呢!注意这里pushup也值得好好琢磨琢磨。
下面是核心代码query函数:
先看这个函数是node类型的,就很不一样!
我的想法:为了保证答案正确(所求区间是完整的且不是重复的)就要用这种结点的形式,而不能采用简单的两边最大和相加!代码如下!
node query(int k,int l,int r){//注意这里求最大子段和就不是原来那样了!!!
if(l<=t[k].l&&t[k].r<=r){
return t[k];
}else{
int mid=(t[k].l+t[k].r)>>1;
if(r<=mid) return query(k<<1,l,r);
else if(l>mid) return query(k<<1|1,l,r);
else{
node a,b,c;
a=query(k<<1,l,mid);
b=query(k<<1|1,mid+1,r);
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.mmax=max(max(a.mmax,b.mmax),a.rmax+b.lmax);
return c;
}
}
}
下面是AC代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#define ll long long
#define inf 0x3f3f3f3f
#define cl(a,b) memset(a,b,sizeof(a))
using namespace std;
const int maxn=50000+5;
int n,m;
int a[maxn];
struct node{
int l,r,lmax,rmax,mmax,sum;
}t[maxn<<2];
void pushup(int k){
t[k].sum=t[k<<1].sum+t[k<<1|1].sum;
t[k].lmax=max(t[k<<1].lmax,t[k<<1].sum+t[k<<1|1].lmax);
t[k].rmax=max(t[k<<1|1].rmax,t[k<<1|1].sum+t[k<<1].rmax);
t[k].mmax=max(max(t[k<<1].mmax,t[k<<1|1].mmax),t[k<<1].rmax+t[k<<1|1].lmax);
}
void build(int k,int l,int r){
t[k].l=l,t[k].r=r;
if(l==r){
t[k].sum=t[k].mmax=t[k].lmax=t[k].rmax=a[l];
}else{
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
pushup(k);
}
}
void updata(int k,int p,int v){
if(t[k].l==t[k].r){
if(t[k].l==p){
t[k].sum=t[k].mmax=t[k].lmax=t[k].rmax=v;
}
}else{
int mid=(t[k].l+t[k].r)>>1;
if(p<=mid) updata(k<<1,p,v);
else if(mid<p) updata(k<<1|1,p,v);
pushup(k);
}
}
node query(int k,int l,int r){//注意这里求最大子段和就不是原来那样了!!!
if(l<=t[k].l&&t[k].r<=r){
return t[k];
}else{
int mid=(t[k].l+t[k].r)>>1;
if(r<=mid) return query(k<<1,l,r);
else if(l>mid) return query(k<<1|1,l,r);
else{
node a,b,c;
a=query(k<<1,l,mid);
b=query(k<<1|1,mid+1,r);
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.mmax=max(max(a.mmax,b.mmax),a.rmax+b.lmax);
return c;
}
}
}
int main(){
while(scanf("%d",&n)!=EOF){
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
build(1,1,n);
scanf("%d",&m);
int op,x,y;
while(m--){
scanf("%d%d%d",&op,&x,&y);
if(op==1){
node temp=query(1,x,y);
printf("%d\n",temp.mmax);
}if(op==0){
updata(1,x,y);
}
}
}
return 0;
}
You are given a sequence A of N (N <= 50000) integers between -10000 and 10000. On this sequence you have to apply M (M <= 50000) operations:
modify the i-th element in the sequence or for given x y print max{Ai + Ai+1 + … + Aj | x<=i<=j<=y }.
Input
The first line of input contains an integer N. The following line contains N integers, representing the sequence A1…AN.
The third line contains an integer M. The next M lines contain the operations in following form:
0 x y: modify Ax into y (|y|<=10000).
1 x y: print max{Ai + Ai+1 + … + Aj | x<=i<=j<=y }.
Output
For each query, print an integer as the problem required.
Example
Input:
4
1 2 3 4
4
1 1 3
0 3 -3
1 2 4
1 3 3
Output:
6
4
-3