【题目】
给定长度为N的数列A,以及M条指令,每条指令可能是以下两种之一:
“1 x y”,查询区间 [x,y] 中的最大连续子段和,即
“2 x y”,把 A[x] 改成 y。
对于每个查询指令,输出一个整数表示答案
【题解】
刚开始看的时候,单点更新,区间修改,第一反应就是线段树,但问题就出在求最大连续子段和,这是个麻烦的事情。而解决这个的方法,就是在线段树中放四个值 , 是指在线段树的这个区间内,所有数的和, 指的是这个区间内从最左边开始连续的最大子段和, 指的是这个区间内从最右边开始的最大子段和, 则指的是这个区间内中间最大子段和(跟 和 不同的地方就在于可以不是从极端开始连续)。这么设计线段树,是因为线段树本身具有的特性形成的,从线段树的最底层想想看,是不是每次跟左兄弟姐妹和右兄弟姐妹的合并:
都是
,进而的求出
的最优值,
又都是
,进而的求出
的最优值,
又都是
,进而的求出
的最优值。
那么到了最后,是不是整个线段树的所有的区间只要 就能找到这个区间的最大值。当然查询的过程中,还是需要合并被分开来的区间的,这个的话,可以看看我的线段树查询代码。还有就是因为是单点更新,所以不需要懒标记。
时间复杂度:线段树的建树复杂度 ,查询复杂度 ,更新复杂度 ,此题整体复杂度
#include<iostream>
#include<cstring>
#include<sstream>
#include<string>
#include<cstdio>
#include<cctype>
#include<vector>
#include<queue>
#include<cmath>
#include<stack>
#include<set>
#include<map>
#include<algorithm>
#define fi first
#define se second
#define MP make_pair
#define P pair<int,int>
#define PLL pair<ll,ll>
#define Sca(x) scanf("%d",&x)
#define Sca2(x,y) scanf("%d%d",&x,&y)
#define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define Scl(x) scanf("%ld",&x)
#define Scll(x) scanf("%lld",&x)
#define Pri(x) printf("%d\n",x);
#define Prl(x) printf("%lld\n",x);
#define For(i,x,y) for(int i=x;i<=y;i++)
#define _For(i,x,y) for(int i=x;i>=y;i--)
#define FAST_IO std::ios::sync_with_stdio(false)
#define ll long long
const int INF=0x3f3f3f3f;
const ll INFL=0x3f3f3f3f3f3f3f3f;
const double Pi = acos(-1.0);
using namespace std;
template <class T>void tomax(T&a,T b){ a=max(a,b); }
template <class T>void tomin(T&a,T b){ a=min(a,b); }
const int N=5e5+5;
struct SEG{
struct Tree{
int l,r;
int ans,lmax,rmax,dat;
}tree[N<<2];
#define lc (p<<1)
#define rc ((p<<1)|1)
#define MID (tree[p].l+tree[p].r)>>1
void pushup(int p){
tree[p].ans=tree[lc].ans+tree[rc].ans;
tree[p].lmax=max(tree[lc].lmax,tree[lc].ans+tree[rc].lmax);
tree[p].rmax=max(tree[rc].rmax,tree[rc].ans+tree[lc].rmax);
tree[p].dat=max(tree[lc].dat,max(tree[rc].dat,tree[lc].rmax+tree[rc].lmax));
}
void build(int l,int r,int p){
tree[p].l=l;
tree[p].r=r;
tree[p].ans=0;
if(l==r){
int x; Sca(x);
tree[p].ans=tree[p].lmax=tree[p].rmax=tree[p].dat=x;
return ;
}
int mid=MID;
build(l,mid,lc);
build(mid+1,r,rc);
pushup(p);
}
void updata(int id,int p,int val){
if(tree[p].l==id&&tree[p].r==id){
tree[p].ans=tree[p].lmax=tree[p].rmax=tree[p].dat=val;
return ;
}
int mid=MID;
if(id<=mid) updata(id,lc,val);
else updata(id,rc,val);
pushup(p);
}
Tree query(int l,int r,int p){
if(tree[p].l>=l&&tree[p].r<=r){
return tree[p];
}
int mid=MID;
if(r<=mid) return query(l,r,lc);
else if(l>mid) return query(l,r,rc);
else{
Tree x,t1=query(l,r,lc),t2=query(l,r,rc);
x.lmax=max(t1.lmax,t1.ans+t2.lmax);
x.rmax=max(t2.rmax,t2.ans+t1.rmax);
x.dat=max(t1.dat,max(t2.dat,t1.rmax+t2.lmax));
return x;
}
}
int get(int l,int r){
Tree now=query(l,r,1);
int maxx=now.lmax;
tomax(maxx,now.rmax);
tomax(maxx,now.dat);
return maxx;
}
};
SEG go;
int main(){
int n,m; Sca2(n,m);
go.build(1,n,1);
while(m--){
int op,x,y; Sca3(op,x,y);
if(op==1){
if(x>y) swap(x,y);
Pri(go.get(x,y));
}
else go.updata(x,1,y);
}
}