zoukankan      html  css  js  c++  java
  • 题解 SP1716 【GSS3

    前言

    首先说一下题意。就是每次给出 (x)(y) 两个数,求 (x)(y) 这个区间的最大子段和

    正文

    分析

    首先我们看这个数据范围,我们显然是要用线段树来做这道题。

    我们考虑如何pushup

    pushup的操作

    360截图17001020107151123.png

    区间最大字段和

    我们考虑一个区间的最大子段

    我们分 (3) 种情况讨论

    1. 有可能是左边部分的最大子段和

    asdsajdfhiujhkja.png

    答案就是左边部分的最大子段和

    2. 也有可能右边部分的最大子段和

    asdasajdfhiujhkja.png

    答案就是右边部分的最大子段和

    3. 最大最大和有可能跨越了中间

    aasdasajdfhiujhkja.png

    答案就是左边部分右端点往左的最大子段和 (+) 左端点往右的最大子段和

    发现

    所以,我们需要对于所有节点,还要维护它们以左端点往右的最大子段和、右端点往左的最大子段和。

    我们再考虑如何维护一个区间以左端点往右的最大子段和、右端点往左的最大子段和。

    以左端点往右的最大子段和

    我们先考虑以左端点往右的最大子段和

    我们分 (2) 种情况讨论

    1. 不跨越中间

    aaasajdfhiujhkja.png

    答案就是左部分的以左端点往右的最大子段和

    2. 跨越中间

    asdssssajdfhiujhkja.png

    答案就是左部分的和 (+) 右部分以左端点往右的最大子段和

    以右端点往左的最大子段和

    我们先考虑以右端点往左的最大子段和

    我们分 (2) 种情况讨论

    1. 不跨越中间

    kja.png

    答案就是右部分的以左端点往右的最大子段和

    2. 跨越中间

    df.png

    答案就是右部分的和 (+) 左部分以右端点往左的最大子段和

    发现

    我们发现我们还需要维护区间和,这个问题很简单,不在讲解了。

    所以我们现在总共要维护 (4) 个东西

    分别是

    (lans)(rans)(ans)(sum)

    边界情况——即整个区间是一个点

    我们可以发现

    (lans)(rans)(ans)(sum) 都为这个点的值

    代码

    Tree pushup(Tree L,Tree R){
    	Tree z;
    	z.sum=L.sum+R.sum;//和
    	z.l=max(L.l,L.sum+R.l);//2种情况
    	z.r=max(R.r,R.sum+L.r);//2种情况
    	z.ans=max(max(L.ans,R.ans),L.r+R.l);//3种情况
    	return z;
    }
    

    这里我写了一个带返回值的函数,就是为了下面方便啦。

    查询

    上文已经讲解了最大子段和的 (3) 中情况,已经知道最大子段和跟 (4) 个东西有关。

    所以我们要定义一个返回值为 (Tree) 的函数。

    那么现在,关键就在于合并区间,那么现在之前的pushup就可以被调用了。

    Tree query(int x,int y,int num,int l,int r){
    	if(l<=x&&r<=y)return t[num];
    	int mid=(l+r)>>1;
    	if(y<=mid)return query(x,y,ls,l,mid);//右区间和查询区间没有交,答案当然在左区间
    	if(mid<x)return query(x,y,rs,mid+1,r);//左区间和查询区间没有交,答案当然在右区间
    	return pushup(query(x,mid,ls,l,mid),query(mid+1,y,rs,mid+1,r));//是不是很简洁?
    }
    

    代码

    我们已经把这道题的重点都搞清楚了,接下来就可以放代码了,至于单点修改不会的请自行去学习

    #include <bits/stdc++.h>
    #define ls num<<1
    #define rs num<<1|1
    using namespace std;
    template<typename T>inline void read(T &FF){
    	T RR=1;FF=0;char CH=getchar();
    	for(;!isdigit(CH);CH=getchar())if(CH=='-')RR=-1;
    	for(;isdigit(CH);CH=getchar())FF=(FF<<1)+(FF<<3)+(CH^48);
    	FF*=RR;
    }
    template<typename T>void write(T x){
    	if(x<0)putchar('-'),x*=-1;
    	if(x>9)write(x/10);
    	putchar(x%10+48);
    }
    template<typename T>void writen(T x){
    	write(x);
    	puts("");
    }
    const int MAXN=5e4+10;
    struct Tree{
    	int sum,l,r,ans;//维护的4个量
    }t[MAXN*4];
    int a[MAXN],f,x,y;
    Tree pushup(Tree L,Tree R){
    	Tree z;
    	z.sum=L.sum+R.sum;//和
    	z.l=max(L.l,L.sum+R.l);//2种情况
    	z.r=max(R.r,R.sum+L.r);//2种情况
    	z.ans=max(max(L.ans,R.ans),L.r+R.l);//3种情况
    	return z;
    }
    void build(int l,int r,int num){//建树
    	if(l==r){
    		t[num].sum=a[l];
    		t[num].l=a[l];
    		t[num].r=a[l];
    		t[num].ans=a[l];//边界初始化
    		return;
    	}
    	int mid=(l+r)>>1;
    	build(l,mid,ls);
    	build(mid+1,r,rs);
    	t[num]=pushup(t[ls],t[rs]);//pushup
    }
    void change(int l,int r,int num){//单点修改
    	if(l==r){
    		t[num].sum=y;
    		t[num].l=y;
    		t[num].r=y;
    		t[num].ans=y;//边界初始化
    		return;
    	}
    	int mid=(l+r)>>1;
    	if(x<=mid)change(l,mid,ls);
    	else change(mid+1,r,rs);
    	t[num]=pushup(t[ls],t[rs]);
    }
    Tree query(int x,int y,int num,int l,int r){
    	if(l<=x&&r<=y)return t[num];
    	int mid=(l+r)>>1;
    	if(y<=mid)return query(x,y,ls,l,mid);//右区间和查询区间没有交,答案当然在左区间
    	if(mid<x)return query(x,y,rs,mid+1,r);//左区间和查询区间没有交,答案当然在右区间
    	return pushup(query(x,mid,ls,l,mid),query(mid+1,y,rs,mid+1,r));//是不是很简洁?
    }
    int main(){
    	int n,T;
    	read(n);
    	for(int i=1;i<=n;i++)read(a[i]);
    	build(1,n,1);
    	read(T);
    	while(T--){
    		read(f);read(x);read(y);
    		if(f==0)change(1,n,1);
    		else writen(query(x,y,1,1,n).ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    最小树形图 朱刘算法模板+建边技巧
    模板倍增LCA 求树上两点距离 hdu2586
    【瞎搞题】gym226123 L. For the Honest Election
    【凸包板题】Gym
    集合3
    集合2
    集合1
    常用API&异常
    内部类&API
    多态&接口类&接口
  • 原文地址:https://www.cnblogs.com/zhaohaikun/p/12817040.html
Copyright © 2011-2022 走看看