p1115 最大子段和(线段树)

题目描述-->p1115 最大子段和

虽然是一个普及-的题,但我敲了线段树 qwq

数组定义

\(lsum[ ]\)代表 该区间左端点开始的最大连续和.

\(rsum[ ]\)代表 该区间右端点开始的最大连续和.

\(ssum[ ]\)代表 区间内最大连续和.

\(sum[ ]\) 代表区间和.

Que and A

Q:已知一个区间的左右区间的最大连续和,如何合并?

A:这个区间的最大连续和要么是左子区间的最大连续和,要么是右子区间的最大连续和.

 要么是左子区间的最大右起子段和+右子区间的最大左起字段和.

code:\(ssum[o]=max(max(ssum[lson],ssum[rson]),rsum[lson]+lsum[rson])\)

Q:如何更新区间最大左起子段和.

A:新区间的最大左起子段和.要么是其左子区间最大连续和,要么是其左子区间和+右子区间的左起子段和.

最大右起子段和同理

code:\(lsum[o]=max(lsum[lson],sum[lson]+lsum[rson])\)

     \(rsum[o]=max(rsum[rson],sum[rson]+rsum[lson])\)

更新操作类似单点修改

贴一下代码 qwq.

#include<bits/stdc++.h>
#define IL inline
#define int long long
#define RI register int
#define N 200008
#define ls o<<1
#define rs o<<1|1
using namespace std;
IL void in(int &x)
{
    int f=1;x=0;char s=getchar();
    while(s>'9' or s<'0'){if(s=='-')f=-1;s=getchar();}
    while(s>='0' and s<='9'){x=x*10+s-'0';s=getchar();}
    x*=f;
}
int tr[N<<2],ssum[N<<2],lsum[N<<2],rsum[N<<2],n;
IL void up(int o)
{
    tr[o]=tr[ls]+tr[rs];
    ssum[o]=max(max(ssum[ls],ssum[rs]),rsum[ls]+lsum[rs]);
    lsum[o]=max(lsum[ls],tr[ls]+lsum[rs]);
    rsum[o]=max(rsum[rs],tr[rs]+rsum[ls]);
}
IL void build(int o,int l,int r)
{
    if(l==r)
    {
        in(tr[o]);
        ssum[o]=lsum[o]=rsum[o]=tr[o];
        return;
    }
    int mid=(l+r)>>1;
    build(ls,l,mid);
    build(rs,mid+1,r);
    up(o);
}
IL int query(int o,int l,int r,int x,int y)
{
    if(l<=x and y>=r)return ssum[o];
    int mid=(l+r)>>1;
    int ret=-2147483647;
    if(x<=mid)ret=max(query(ls,l,mid,x,y),ret);
    if(y>mid)ret=max(query(rs,mid+1,r,x,y),ret);
    return ret;
}

main(void )
{
    in(n);
    build(1,1,n);
    printf("%lld",query(1,1,n,1,n));
}

原文地址:https://www.cnblogs.com/-guz/p/9690947.html

时间: 2024-08-30 16:05:30

p1115 最大子段和(线段树)的相关文章

SPOJ 1043 Can you answer these queries I 求任意区间最大连续子段和 线段树

题目链接:点击打开链接 维护区间左起连续的最大和,右起连续的和.. #include <cstdio> #include <iostream> #include <algorithm> #include <string.h> #include <math.h> #include <vector> #include <map> using namespace std; #define N 50050 #define Lson

SPOJ GSS系列 最大子段和 线段树+树链剖分+splay 1043 1557 1716 2713 2916 4487 6779

最大子段和的各种形式 题解内附每道题的 题意 题目链接 思路 SPOJ 1043 GSS1 静态区间求个最大子段和, 题解 SPOJ 1577 GSS2 和1一样,区别是若区间内存在相同的元素,则该元素只计算一次. 离线一下然后使劲跑.. 题解 SPOJ 1716 GSS3 和1一样,就是要支持单点修改 题解 SPOJ 2713 GSS4 ==普通线段树,感觉和这系列关系不大. 题解 SPOJ 2916 GSS5 题意有点怪,,跟3差不多,就是稍加强了点询问 题解 SPOJ 4487 GSS6

codevs 3981 动态最大子段和(线段树)

题目传送门:codevs 3981 动态最大子段和 题目描述 Description 题目还是简单一点好... 有n个数,a[1]到a[n]. 接下来q次查询,每次动态指定两个数l,r,求a[l]到a[r]的最大子段和. 子段的意思是连续非空区间. 输入描述 Input Description 第一行一个数n. 第二行n个数a[1]~a[n]. 第三行一个数q. 以下q行每行两个数l和r. 输出描述 Output Description q行,每行一个数,表示a[l]到a[r]的最大子段和. 样

线段树维护区间最大子段和

线段树:我还是很强的 简略讲解 要用线段树维护区间,我们要明确: 线段树存什么东西 怎么合并 如果有区间修改,怎么打标记 对于区间最大子段和,我们可以记录四个值:以维护的区间左端点为起点的最大子段和,以维护的区间右端点为终点的最大子段和,在维护区间内的最大子段和 和维护区间所有元素的和 合并的话稍微麻烦一些,看代码吧: inline void up(int p){ tree[p].sum=tree[ls].sum+tree[rs].sum; //维护区间总和 tree[p].ll=max(tre

线段树维护区间最大子段和 枚举 HDU6638

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6638 题意:在一个二维坐标系上给你n(n<=2000)个点,点带有一个价值w(有正有负),点的坐标都在(-1e9,1e9)的范围之间,可任意用一个平行于坐标轴的矩形框住一片区域,求这片区域框住的点的价值和 分析:点的坐标范围太大,离散化应能想到.离散化后可以考虑枚举左边界,枚举左边界后按照横坐标的依次加点(以一列一列为单位),用线段树维护一列的最大子段和,每移动到新的一列,继续加点时,等价于向原先的

HDU6638 Snowy Smile (线段树+二维最大子段和)

2019杭电多校第六场的一道签到题 这次我们显然要求的二维矩阵的最大值,分析题目我们可以得到几个细节. 1.首先数据很大,肯定要离散化. 2.离散化后,我们想象有很多点在一个平面内,要统计矩阵最大值 3.我们之前接触过如何求一条线上的最大子段和,只要用线段树维护四个值就能够解决 4.根据已知,我们发现求矩阵和也是可以这么做的,因为他是一个矩形,所以我们假如我们有两行,其实可以把第二行的对应数据加到第一行上去,进行压维操作,再求一维的最大子段和. 5.我们要考虑所有的情况,因此我们以x轴作为线段树

bzoj 2482: [Spoj GSS2] Can you answer these queries II 线段树

2482: [Spoj1557] Can you answer these queries II Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 145  Solved: 76[Submit][Status][Discuss] Description 给定n个元素的序列. 给出m个询问:求l[i]~r[i]的最大子段和(可选空子段). 这个最大子段和有点特殊:一个数字在一段中出现了两次只算一次. 比如:1,2,3,2,2,2出现了3次,但只算一次,

HDU 4902 线段树(区间更新)

Nice boat Time Limit: 30000/15000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 353    Accepted Submission(s): 169 Problem Description There is an old country and the king fell in love with a devil. The devil alw

浅谈线段树

 数据结构——线段树 O.引例 A.给出n个数,n<=100,和m个询问,每次询问区间[l,r]的和,并输出. 一种回答:这也太简单了,O(n)枚举搜索就行了. 另一种回答:还用得着o(n)枚举,前缀和o(1)就搞定. 那好,我再修改一下题目. B.给出n个数,n<=100,和m个操作,每个操作可能有两种:1.在某个位置加上一个数:2.询问区间[l,r]的和,并输出. 回答:o(n)枚举. 动态修改最起码不能用静态的前缀和做了. 好,我再修改题目: C.给出n个数,n<=1000000,