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;
    }
    
  • 相关阅读:
    机器学习到深度学习资料
    安装CentOS 6停在selinux-policy-targeted卡住的问题解决
    U盘安装Ubuntu 16.04出现:Failed to load ldlinux.c32
    Ubuntu 16.04下使用UNetbootin制作的ISO镜像为U盘启动出现:Missing Operating System (mbr.bin)
    为什么Linux的Fdisk分区时First Sector为2048?
    Windows下将ISO镜像制作成U盘启动的工具(U盘启动工具/UltraISO/Rufus/Universal-USB)
    CentOS 6.9安装类型选择(Basic Server/Web Server)
    Java中String与byte[]的转换
    IntelliJ IDEA插件-翻译插件
    Mycat查询时出现:Error Code: 1064. can't find any valid datanode
  • 原文地址:https://www.cnblogs.com/zhaohaikun/p/12427723.html
Copyright © 2011-2022 走看看