洛谷 SP1716 GSS3 - Can you answer these queries III

题目链接

话说真的和GSS1有什么区别,除了一个修改操作...

0x00 思路

最大子段和是区间内一段连续元素的和,不妨当成一段区间来看,那么对于一段区间\([l,r]\)的最大子段和,有存在三种情况

定义\(mid = (l + r) / 2\)

  1. 完全位于\([l,mid]\)

  2. 完全位于\([mid+1,r]\)

  3. 左端点在\([l,mid]\),右端点在\([mid+1,r]\)

这样,维护区间最大子段和,我们就要知道以下三个值:

  1. 子区间最大子段和

  2. 左区间的最大后缀和

  3. 右区间的最大前缀和

对于(1)我们很好理解,那么(2)(3)呢?

当左右端点分居在两个区间内时,我们发现它们之间没有关系,就是由一段前缀,一段后缀连接而成,分开讨论即可

接下来,为了维护最大前/后缀和,我们又要知道以下六个值

  1. 左区间的区间和/最大前缀和/最大后缀和

  2. 右区间的区间和/最大前缀和/最大后缀和

最大前缀和 = max(左区间最大前缀和 , 左区间区间和 + 右区间最大前缀和)

最大后缀和 = max(右区间最大后缀和 , 右区间区间和 + 左区间最大后缀和)

这下解决了,可以上线段树维护了

你问我区间和怎么维护?我只能呵呵

0x01 Code

#include<bits/stdc++.h>
using namespace std;
#define mid ((l+r)>>1)
#define ls (nod<<1)
#define rs (nod<<1|1)
#define lson ls,l,mid
#define rson rs,mid+1,r

int read(){
	int x=0; char c=getchar(); int flag=1;
	while(!isdigit(c)) { if(c=='-') flag=-1; c=getchar(); }
	while(isdigit(c)) { x=((x+(x<<2))<<1)+(c^48); c=getchar(); }
	return x*flag;
}

const int N=5e5+50;

int n,q;

struct Node{
    int l,r;
    int lv,rv,v,sum;
    
}t[N<<2];

Node Union(Node a,Node b){
    Node c;
    c.l=a.l; c.r=b.r;
    c.lv=max(a.lv,a.sum+b.lv);
    c.rv=max(b.rv,b.sum+a.rv);
    c.sum=a.sum+b.sum;
    c.v=max(max(a.v,b.v),a.rv+b.lv);
    return c;
}

void pushup(int nod){
    if(t[nod].l==t[nod].r) return ;
    t[nod]=Union(t[ls],t[rs]);
}

void build(int nod,int l,int r){
    t[nod].l=l; t[nod].r=r;
    if(l==r){
	    t[nod].sum=t[nod].lv=t[nod].rv=t[nod].v=read();
	    return ;
	}
	build(lson); build(rson);
	pushup(nod);
}

void update(int nod,int l,int r,int ps,int val){
    if(l==r){
	    t[nod].lv=t[nod].rv=t[nod].v=t[nod].sum=val;
	    return ;
	}
	if(ps<=mid) update(lson,ps,val);
	else update(rson,ps,val);
	pushup(nod);
}

Node query(int nod,int l,int r,int ll,int rr){
    if(ll==l&&r==rr){
	    return t[nod];
	}
	if(rr<=mid) return query(lson,ll,rr);
	else if(ll>mid) return query(rson,ll,rr);
	else return Union(query(lson,ll,mid),query(rson,mid+1,rr));
}

signed main(){
    n=read();
    build(1,1,n);
    q=read();
    while(q--){
	    int opt=read(),x=read(),y=read();
	    if(opt==0){
		    update(1,1,n,x,y);
		}else{
		    printf("%d\n",query(1,1,n,x,y).v);
		}
	}
    return 0;
}

posted @ 2020-01-29 16:28  zhuzihan  阅读(132)  评论(0编辑  收藏  举报