【题目】
给定长度为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); } }