zoukankan      html  css  js  c++  java
  • 线段树 小白逛公园

    线段树动态维护区间最大子段和。

    同机房的大佬们都做完这道题啦,我也要补一补这个坑了。

    GXZ大佬给我们讲过一遍,不过好像忘记了。。。

    但是这道题确实不难,就是一个比较考思维的区间合并题。

    我们最终的目的就是求区间的最大子段和,所以我们就要处理出一些东西,使得小区间可以推出大区间的数据。

    (由小推大是线段树的思想不是吗)

    那么对于区间o,他的数据要由(ls(o))(rs(o))来推出,那么考虑区间o的最大子段和会是什么状态?

    一,全部在左区间里。二,全部在右区间里。三,跨过中间点有左区间的一部分和右区间的一部分。

    对于一,二好说,直接由左右区间的最大子段和转移就行。

    对于三的话,就不能有左右区间的最大子段和去更新了。那怎么办呢?

    我们可以维护每个区间的:以左端点为起点的最大子段和和以右端点为终点的最大子段和。

    那么既然引进了新的数据量,自然也要去维护。

    又因为对称性,我们这里只讲如何维护以左端点为起点的最大子段和,另一部分直接可以由对称得到。

    如何维护呢?

    首先很容易想到可以直接由左区间的该数据推出,另外,我们还可以发现,右区间其实也可以对这一数据的更新做出贡献。

    也就是我们把左区间全部选择,为了保证最优还要选上右区间的左端点为起点的最大子段和。

    这就可以轻松的维护了。

    但是又引入了一个量,那就是区间内所有数的总和,但是这个很容易维护。

    这次,问题就得到了解决。(果真是一个不断挖坑填坑的过程呢)。

    核心代码就是更新,应好好理解。

    void up(int o){
    	tot(o)=tot(ls(o))+tot(rs(o));
    	lsum(o)=max(lsum(ls(o)),tot(ls(o))+lsum(rs(o)));
    	rsum(o)=max(rsum(rs(o)),tot(rs(o))+rsum(ls(o)));
    	sum(o)=max(max(sum(ls(o)),sum(rs(o))),rsum(ls(o))+lsum(rs(o)));
    }
    

    另外对于单点修改,直接修改然后up自下到上维护一下就可以了。

    对于区间查询,可以采用递归的思想(或者说分治?)

    如果询问区间在当前区间的左半区间内 ,则向左递归,若在右半区间内,则向右递归。

    若跨过了当前区间的中点,则向左求一部分答案再向右求一部分答案,之后类似up地做法把答案合并一下就可以了。

    code:

    #include<iostream>
    #include<cstdio>
    #define ls(o) o<<1
    #define rs(o) o<<1|1
    using namespace std; 
    const int wx=7000017;
    inline int read(){
    	int sum=0,f=1;
    	char ch=getchar();
    	while(ch<'0'||ch>'9'){
    		if(ch=='-')f=-1;
    		ch=getchar();
    	}
    	while(ch>='0'&&ch<='9'){
    		sum=(sum<<1)+(sum<<3)+ch-'0';
    		ch=getchar();
    	}
    	return sum*f;
    }
    struct val_tree{
    	int l,r;
    	int sum,lsum,rsum,tot;
    	#define sum(o) t[o].sum
    	#define lsum(o) t[o].lsum
    	#define rsum(o) t[o].rsum
    	#define tot(o) t[o].tot
    }t[wx*4];
    int n,m,x,y,opt;
    int a[wx];
    void up(int o){
    	tot(o)=tot(ls(o))+tot(rs(o));
    	lsum(o)=max(lsum(ls(o)),tot(ls(o))+lsum(rs(o)));
    	rsum(o)=max(rsum(rs(o)),tot(rs(o))+rsum(ls(o)));
    	sum(o)=max(max(sum(ls(o)),sum(rs(o))),rsum(ls(o))+lsum(rs(o)));
    }
    void build(int o,int l,int r){
    	t[o].l=l;t[o].r=r;
    	if(l==r){tot(o)=sum(o)=lsum(o)=rsum(o)=a[l];return;}
    	int mid=t[o].l+t[o].r>>1;
    	if(l<=mid)build(ls(o),l,mid);
    	if(r>mid)build(rs(o),mid+1,r);
    	up(o);
    }
    void update(int o,int l,int r,int k){
    	if(l<=t[o].l&&t[o].r<=r){
    		tot(o)=sum(o)=lsum(o)=rsum(o)=k;
    		return;
    	}
    	int mid=t[o].l+t[o].r>>1;
    	if(l<=mid)update(ls(o),l,r,k);
    	if(r>mid)update(rs(o),l,r,k);
    	up(o);
    }
    val_tree query(int o,int l,int r){
    	if(l<=t[o].l&&t[o].r<=r){
    		return t[o];
    	}
    	int mid=t[o].l+t[o].r>>1;
    	if(r<=mid)return query(ls(o),l,r);
    	else if(l>mid)return query(rs(o),l,r);
    	else{
    		val_tree tmp;
    		val_tree tmp_l,tmp_r;
    		tmp_l=query(ls(o),l,r);tmp_r=query(rs(o),l,r);
    		tmp.tot=tmp_l.tot+tmp_r.tot;
    		tmp.lsum=max(tmp_l.lsum,tmp_l.tot+tmp_r.lsum);
    		tmp.rsum=max(tmp_r.rsum,tmp_r.tot+tmp_l.rsum);
    		tmp.sum=max(max(tmp_l.sum,tmp_r.sum),tmp_l.rsum+tmp_r.lsum);
    		return tmp;
    	}
    }
    int main(){
    	n=read();m=read();
    	for(int i=1;i<=n;i++)a[i]=read();
    	build(1,1,n);
    	for(int i=1;i<=m;i++){
    		opt=read();x=read();y=read();
    		if(x>y&&opt==1)swqp(x,y);
    		if(opt==1)printf("%d
    ",query(1,x,y).sum);
    		else update(1,x,x,y);
    	}
    	return 0;
    }
    
  • 相关阅读:
    null和undefined的区别
    "NetworkError: 404 Not Found fontawesome-webfont.woff?v=4.0.3
    php字符串
    php数组
    Oracle 和 MySQL的区别(不完整)
    拦截器和过滤器的区别
    SpringMVC和Struts2的区别
    Redis的介绍
    SpringBoot入门(2)
    SpringBoot入门(1)
  • 原文地址:https://www.cnblogs.com/wangxiaodai/p/9744081.html
Copyright © 2011-2022 走看看