zoukankan      html  css  js  c++  java
  • 线段树区间最大子段和

    线段树区间最大子段和

    应用场景

    支持单点修改时维护区间的最大字段和

    核心思想

    利用线段树的分治思想,区间内的子段可以分为完全在左侧的,穿过中点的和完全在右侧的。

    实现

    维护区间最大字段和基于不带lazy_tag的线段树,只需要将状态由和变为结构体即可。
    首先,我们定义一种结构体,包含区间和,从左侧开始的最大字段和,从右侧开始的最大字段和与没有要求的最大字段和。

    struct node{
    	LL sum,maxl,maxr,maxv;
    	node(){
    		sum=maxl=maxr=maxv=0;
    	}
    };
    

    对于一个区间,我们只需要将其分成左右两个部分,按照下面的代码更新即可。

    inline void push_up(int x){
    	A[x].sum=A[x<<1].sum+A[x<<1|1].sum;
    	A[x].maxl=max(A[x<<1].maxl,A[x<<1].sum+A[x<<1|1].maxl);
    	A[x].maxv=max(A[x<<1].maxr+A[x<<1|1].maxl,max(A[x<<1].maxv,A[x<<1|1].maxv));
    	A[x].maxr=max(A[x<<1|1].maxr,A[x<<1].maxr+A[x<<1|1].sum);
    }
    

    在操作中,建树、单点修改都是正常的,只需要设计区间查询最大字段和。
    此处我们返回一个结构体,包含查询范围内的状态,每次按照分治的规则归并即可

    node query(int x,int l,int r,int ql,int qr){
    	if(ql<=l&&r<=qr){
    		return A[x];
    	}
    	int mid=(l+r)>>1;
    	if(qr<=mid)
    		return query(x<<1,l,mid,ql,qr);
    	if(ql>mid)
    		return query(x<<1|1,mid+1,r,ql,qr);
    	node left=query(x<<1,l,mid,ql,qr),right=query(x<<1|1,mid+1,r,ql,qr),ret;
    	ret.maxv=max(left.maxr+right.maxl,max(left.maxv,right.maxv));
    	ret.maxl=max(left.maxl,left.sum+right.maxl);
    	ret.maxr=max(right.maxr,left.maxr+right.sum);
    	return ret;
    }
    

    例题

    [Luogu P4513 小白逛公园](%3Ca href="https://www.luogu.org/problemnew/show/P4513"%3Ehttps://www.luogu.org/problemnew/show/P4513%3C/a%3E)

    题目描述

    在小新家附近有一条“公园路”,路的一边从南到北依次排着nn个公园,小白早就看花了眼,自己也不清楚该去哪些公园玩了。一开始,小白就根据公园的风景给每个公园打了分-.-。小新为了省事,每次遛狗的时候都会事先规定一个范围,小白只可以选择第aa个和第bb个公园之间(包括aa、bb两个公园)选择连续的一些公园玩。小白当然希望选出的公园的分数总和尽量高咯。同时,由于一些公园的景观会有所改变,所以,小白的打分也可能会有一些变化。那么,就请你来帮小白选择公园吧。

    输入输出格式

    输入格式:

    第一行,两个整数NN和MM,分别表示表示公园的数量和操作(遛狗或者改变打分)总数。
    接下来NN行,每行一个整数,依次给出小白 开始时对公园的打分。
    接下来MM行,每行三个整数。第一个整数KK,11或22。K=1K=1表示,小新要带小白出去玩,接下来的两个整数aa和bb给出了选择公园的范围(1≤a,b≤N1≤a,b≤N)。测试数据可能会出现a>ba>b的情况,需要进行交换;K=2K=2表示,小白改变了对某个公园的打分,接下来的两个整数pp和ss,表示小白对第pp个公园的打分变成了ss(1≤p≤N1≤p≤N)。
    其中,1≤N≤500 0001≤N≤500000,1≤M≤100 0001≤M≤100000,所有打分都是绝对值不超过10001000的整数。

    输出格式:

    小白每出去玩一次,都对应输出一行,只包含一个整数,表示小白可以选出的公园得分和的最大值。输入输出样例输入样例#1: 
    5 3
    1 2 -3 4 5
    1 2 3
    2 2 -1
    1 2 3
    输出样例#1: 
    2
    -1

    题解

    这道题是模板题,直接给出代码

    using namespace std;
    typedef long long LL;
    const int INF=1e9+7,MAXN=5e5+10,MAXNODE=MAXN<<2,MAXM=1e5+10;
    int N,M;
    LL tmp[MAXN];
    struct node{
    	LL sum,maxl,maxr,maxv;
    	node(){
    		sum=maxl=maxr=maxv=0;
    	}
    }A[MAXNODE];
    inline void push_up(int x){
    	A[x].sum=A[x<<1].sum+A[x<<1|1].sum;
    	A[x].maxl=max(A[x<<1].maxl,A[x<<1].sum+A[x<<1|1].maxl);
    	A[x].maxv=max(A[x<<1].maxr+A[x<<1|1].maxl,max(A[x<<1].maxv,A[x<<1|1].maxv));
    	A[x].maxr=max(A[x<<1|1].maxr,A[x<<1].maxr+A[x<<1|1].sum);
    }
    void init(int x,int l,int r){
    	if(l==r){
    		A[x].sum=A[x].maxl=A[x].maxr=A[x].maxv=tmp[l];
    		return;
    	}
    	int mid=(l+r)>>1;
    	init(x<<1,l,mid);
    	init(x<<1|1,mid+1,r);
    	push_up(x);
    }
    void update(int x,int l,int r,int q,LL c){
    	if(l==r){
    		if(l==q)
    			A[x].sum=A[x].maxl=A[x].maxr=A[x].maxv=c;
    		return;
    	}
    	int mid=(l+r)>>1;
    	if(q<=mid)
    		update(x<<1,l,mid,q,c);
    	else
    		update(x<<1|1,mid+1,r,q,c);
    	push_up(x);
    }
    node query(int x,int l,int r,int ql,int qr){
    	if(ql<=l&&r<=qr){
    		return A[x];
    	}
    	int mid=(l+r)>>1;
    	if(qr<=mid)
    		return query(x<<1,l,mid,ql,qr);
    	if(ql>mid)
    		return query(x<<1|1,mid+1,r,ql,qr);
    	node left=query(x<<1,l,mid,ql,qr),right=query(x<<1|1,mid+1,r,ql,qr),ret;
    	ret.maxv=max(left.maxr+right.maxl,max(left.maxv,right.maxv));
    	ret.maxl=max(left.maxl,left.sum+right.maxl);
    	ret.maxr=max(right.maxr,left.maxr+right.sum);
    	return ret;
    }
    int main(){
    	scanf("%d%d",&N,&M);
    	for(int i=1;i<=N;i++)
    		scanf("%lld",tmp+i);
    	init(1,1,N);
    	int ii,jj,kk;
    	LL ll;
    	for(int i=1;i<=M;i++){
    		scanf("%d",&ii);
    		if(ii==1){
    			scanf("%d%d",&jj,&kk);
    			if(jj>kk)
    				swap(jj,kk);
    			printf("%lld
    ",query(1,1,N,jj,kk).maxv);
    		}else{
    			scanf("%d%lld",&jj,&ll);
    			update(1,1,N,jj,ll);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    2019暑假中山纪中集训游记
    pytest入门学习(1)
    学习makefile与autoconfig笔记,持续更新
    新手安装 hadoop、hive和hbase 笔记
    新装ubuntu 12.04 , 使用技巧
    JDK1.7 和 jetty配置教程
    python成长之路一
    IDM下载神器
    测试
    Hadoop命令
  • 原文地址:https://www.cnblogs.com/guoshaoyang/p/11277792.html
Copyright © 2011-2022 走看看