传送门:>Here<

题意:求区间最大子段和 $N \leq 50000$ 包括多组询问(不需要支持修改)

解题思路

线段树的一道好题

我们可以考虑,如果一组数据全部都是正数,那么问题等同于是查询区间和。然而如果有负数的存在,问题就不一样了

考虑对于每一个节点,维护四个信息:ls(代表当前区间一定顶着左端点的最大子段和),rs(同理,一定顶着右端点的),sum(区间和),val(最大子段和,也就是答案)

考虑进行转移——一个节点的信息由它的两个子节点转移而来

$ls[rt] = Max(ls[rt*2], sum[rt*2] + ls[rt*2+1])$。子段和之所以不包括整段区间是由于右端有负数。因此再往右扩展不会更优

rs同理转移。sum就不说了

$val[rt] = Max\{ val[rt*1], val[rt*1+1], ls[rt], rs[rt], rs[rt*2]+ls[rt*2+1] \}$. 最难理解的是最后一部分。

想象一下,当前区间的最大子段和要么有一头顶住端点,要么两头都不碰到端点。

对于有一头一定碰到的情况,直接用$ls[rt]和rs[rt]$转移即可。(注意,这里所说的是一定碰到,当然最大子段也有可能碰到,但是不一定)

对于都不碰到的情况,如果其不跨过中间,那么分别用两个子节点的val转移。如果恰好跨过中间,那我们需要把它拼接起来——为了使答案最优,我们考虑拼接$rs[rt*2]和ls[rt*2+1]$ (仔细思考)

查询的时候也一样,还是通过递归来完成转移。这里需要对线段树的query有一个较为深刻的理解——不同于build,query(l,r)表示的是区间$[l, r]$中包含在查询区间的那一部分,而不是真的$[l, r]$。因为在递归的时候我们会判断超界。另外,这里的转移需要刚才的四个参数,因此query的返回值应当是一个结构体,而不是单单一个数值。我暂时还没有想出非结构体的做法……

Code

/*By DennyQi*/
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
#define r read()
#define Max(a,b) (((a)>(b)) ? (a) : (b))
#define Min(a,b) (((a)<(b)) ? (a) : (b))
using namespace std;
typedef long long ll;
const int MAXN = ;
const int MAXM = ;
const int INF = ;
inline int read(){
int x = ; int w = ; register int c = getchar();
while(c ^ '-' && (c < '' || c > '')) c = getchar();
if(c == '-') w = -, c = getchar();
while(c >= '' && c <= '') x = (x << ) + (x << ) + c - '', c = getchar(); return x * w;
}
int N,M,x,y,opt,a[MAXN];
struct Data{ int ls,rs,sum,val; };
struct SegmentTree{
int ls[MAXN<<], rs[MAXN<<], sum[MAXN<<], val[MAXN<<];
inline void Pushup(int rt){
sum[rt] = sum[rt<<] + sum[rt<<|];
ls[rt] = Max(ls[rt<<], sum[rt<<]+ls[rt<<|]);
rs[rt] = Max(rs[rt<<|], sum[rt<<|]+rs[rt<<]);
val[rt] = Max(Max(val[rt<<], val[rt<<|]), Max(Max(ls[rt], rs[rt]), rs[rt<<] + ls[rt<<|]));
}
void build(int L, int R, int rt){
if(L >= R){
val[rt] = sum[rt] = ls[rt] = rs[rt] = a[L];
return;
}
int Mid = (L + R) >> ;
build(L, Mid, rt<<);
build(Mid+, R, rt<<|);
Pushup(rt);
}
Data query(int L, int R, int rt, int x, int y){
if(x<=L && R<=y) return (Data){ls[rt],rs[rt],sum[rt],val[rt]};
int Mid = (L + R) >> ;
if(y <= Mid) return query(L, Mid, rt<<, x, y);
if(x >= Mid+) return query(Mid+, R, rt<<|, x, y);
Data res, t_1 = query(L, Mid, rt<<, x, y), t_2 = query(Mid+, R, rt<<|, x, y);
res.sum = t_1.sum + t_2.sum;
res.ls = Max(t_1.ls, t_1.sum + t_2.ls);
res.rs = Max(t_2.rs, t_1.rs + t_2.sum);
res.val = Max(Max(t_1.val, t_2.val), Max(Max(res.ls, res.rs), t_1.rs + t_2.ls));
return res;
}
}qxz;
int main(){
N=r;
for(int i = ; i <= N; ++i) a[i] = r;
qxz.build(, N, );
M=r;
for(int i = ; i <= M; ++i){
x = r, y = r;
printf("%d\n", qxz.query(, N, , x, y).val);
}
return ;
}

[SP1043] GSS1 - Can you answer these queries I的更多相关文章

  1. 线段树 SP1043 GSS1 - Can you answer these queries I

    SP1043 GSS1 - Can you answer these queries I 题目描述 给出了序列A[1],A[2],-,A[N]. (a[i]≤15007,1≤N≤50000).查询定义 ...

  2. SP1043 GSS1 - Can you answer these queries I(线段树,区间最大子段和(静态))

    题目描述 给出了序列A[1],A[2],…,A[N]. (a[i]≤15007,1≤N≤50000).查询定义如下: 查询(x,y)=max{a[i]+a[i+1]+...+a[j]:x≤i≤j≤y} ...

  3. SP1043 GSS1 - Can you answer these queries I(猫树)

    给出了序列A[1],A[2],…,A[N]. (a[i]≤15007,1≤N≤50000).查询定义如下: 查询(x,y)=max{a[i]+a[i+1]+...+a[j]:x≤i≤j≤y}. 给定M ...

  4. SP1043 GSS1 - Can you answer these queries I 线段树

    问题描述 LG-SP1043 题解 GSS 系列第一题. \(q\) 个询问,求 \([x,y]\) 的最大字段和. 线段树,维护 \([x,y]\) 的 \(lmax,rmax,sum,val\) ...

  5. [题解] SPOJ GSS1 - Can you answer these queries I

    [题解] SPOJ GSS1 - Can you answer these queries I · 题目大意 要求维护一段长度为 \(n\) 的静态序列的区间最大子段和. 有 \(m\) 次询问,每次 ...

  6. SPOJ GSS1 - Can you answer these queries I(线段树维护GSS)

    Can you answer these queries I SPOJ - GSS1 You are given a sequence A[1], A[2], -, A[N] . ( |A[i]| ≤ ...

  7. 题解【SP1043】 GSS1 - Can you answer these queries I

    题目描述 You are given a sequence \(A_1, A_2, ..., A_n(|A_i|≤15007,1≤N≤50000)\). A query is defined as f ...

  8. 线段树【SP1043】GSS1 - Can you answer these queries I

    Description 给出了序列\(A_1,A_2,-,A_n\). \(a_i \leq 15007,1 \leq n \leq 50000\).查询定义如下: 查询\((x,y)=max{a_i ...

  9. 「SP1043」GSS1 - Can you answer these queries I

    传送门 Luogu 解题思路 这题就是 GSS3 的一个退化版,不带修改操作的区间最大子段和,没什么好讲的. 细节注意事项 咕咕咕 参考代码 #include <algorithm> #i ...

随机推荐

  1. 十三、MUI的日期起始和结束日期设置

    MUI的日期选择器的使用 // 日期选择器 //生日选择器(不会超过今年) function fdPicker1(id) { var year=new Date().getFullYear(); va ...

  2. Magic Stones CodeForces - 1110E (思维+差分)

    E. Magic Stones time limit per test 1 second memory limit per test 256 megabytes input standard inpu ...

  3. js tool 方法之删除数组指定项

    最近又开始写博文了,还是在自己的本地项目上做一些小的方法案例. 之前撸代码的时候总是遇到删除数组里某个元素的问题,JS没提供便捷的方法,只能自己写个循环处理,所幸自己写个方法,以后博客项目里要用到就不 ...

  4. 多线程系列之八:Thread-Per-Message模式

    一,Thread-Per-Message模式 翻译过来就是 每个消息一个线程.message可以理解为命令,请求.为每一个请求新分配一个线程,由这个线程来执行处理.Thread-Per-Message ...

  5. js文字从左边飞入效果

    贴代码之前,我们先讲一下它的原理,我们使用setInterval,让文字一开始置于屏幕看不到的位置,左右上下都可以,然后让它的位置不断移入到屏幕看得到的位置. 下面上代码: html: <h2 ...

  6. hangfire使用笔记

    1.导入nuget包 2.配置 简单配置后就可以写自己的Job了 注意:Hangfire.RecurringJobExtensions这个扩展支持两种job添加方法:json配置文件和特性.但由于时区 ...

  7. [转帖]浏览器的F5和Ctrl+F5

    浏览器的F5和Ctrl+F5 https://www.cnblogs.com/xiangcode/p/5369084.html 在浏览器里中,按F5键和按F5同时按住Ctrl键(简称Ctrl+F5), ...

  8. Windows 机器上面同时安装mysql5.6 和 mysql5.7 的方法

    1. 自己遇到的两个坑: . mysql 登录的时候 需要使用-P 来指定端口号 不然默认走 呢 . mysql 5.6 和 mysql 5.7 更改用户密码的命令不一样.. 我这边浪费了很长时间: ...

  9. [转帖]xargs命令详解,xargs与管道的区别

    xargs命令详解,xargs与管道的区别 https://www.cnblogs.com/wangqiguo/p/6464234.html 之前一直说要学习一下 xargs 到现在为止也没学习.. ...

  10. Oracle 修改数据库表数据提交之后进行回滚

    --查看历史数据 select * from test1 as of timestamp to_timestamp('2018-12-23 14:41:00', 'yyyy-mm-dd hh24:mi ...