当前位置: 首页 > news >正文

[SP1043] GSS1 - Can you answer these queries I

传送门:>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 = 100010;
const int MAXM = 27010;
const int INF = 1061109567;
inline int read(){
    int x = 0; int w = 1; register int c = getchar();
    while(c ^ '-' && (c < '0' || c > '9')) c = getchar();
    if(c == '-') w = -1, c = getchar();
    while(c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', 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<<2], rs[MAXN<<2], sum[MAXN<<2], val[MAXN<<2];
    inline void Pushup(int rt){
        sum[rt] = sum[rt<<1] + sum[rt<<1|1];
        ls[rt] = Max(ls[rt<<1], sum[rt<<1]+ls[rt<<1|1]);
        rs[rt] = Max(rs[rt<<1|1], sum[rt<<1|1]+rs[rt<<1]);
        val[rt] = Max(Max(val[rt<<1], val[rt<<1|1]), Max(Max(ls[rt], rs[rt]), rs[rt<<1] + ls[rt<<1|1]));
    }
    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) >> 1;
        build(L, Mid, rt<<1);
        build(Mid+1, R, rt<<1|1);
        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) >> 1;
        if(y <= Mid) return query(L, Mid, rt<<1, x, y);
        if(x >= Mid+1) return query(Mid+1, R, rt<<1|1, x, y);
        Data res, t_1 = query(L, Mid, rt<<1, x, y), t_2 = query(Mid+1, R, rt<<1|1, 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 = 1; i <= N; ++i) a[i] = r;
    qxz.build(1, N, 1);
    M=r;
    for(int i = 1; i <= M; ++i){
        x = r, y = r;
        printf("%d\n", qxz.query(1, N, 1, x, y).val);
    }    
    return 0;
}

 

转载于:https://www.cnblogs.com/qixingzhi/p/9435540.html

相关文章:

  • (转)winform之ListView
  • elasticSearch入门
  • ConstraintLayout使用手册
  • 区块链TOP1重入漏洞之自我理解【原创】
  • 阶梯Nim问题
  • python中的函数
  • 织梦dedecms教程简单实现防采集最有效的2个方法
  • mysql清空表数据后如何让自增ID仍从1开始
  • 一、开发基础(4)
  • Vue学习笔记之Webpack介绍
  • 第一次python词云尝试
  • 论优越感
  • 【院校巡礼】em兰州大学/em - 叁研良语的文章 - 知乎
  • μC/OS-III 概述
  • centos6.5使用yum安装redis 设置开机启动
  • gops —— Go 程序诊断分析工具
  • JAVA 学习IO流
  • JavaSE小实践1:Java爬取斗图网站的所有表情包
  • scala基础语法(二)
  • Vue.js-Day01
  • 包装类对象
  • 程序员最讨厌的9句话,你可有补充?
  • 数据结构java版之冒泡排序及优化
  • 正则与JS中的正则
  • MiKTeX could not find the script engine ‘perl.exe‘ which is required to execute ‘latexmk‘.
  • 1.Ext JS 建立web开发工程
  • #Lua:Lua调用C++生成的DLL库
  • #vue3 实现前端下载excel文件模板功能
  • #周末课堂# 【Linux + JVM + Mysql高级性能优化班】(火热报名中~~~)
  • (1)Nginx简介和安装教程
  • (1)STL算法之遍历容器
  • (非本人原创)史记·柴静列传(r4笔记第65天)
  • (附源码)spring boot校园健康监测管理系统 毕业设计 151047
  • (附源码)springboot美食分享系统 毕业设计 612231
  • (论文阅读31/100)Stacked hourglass networks for human pose estimation
  • (区间dp) (经典例题) 石子合并
  • (使用vite搭建vue3项目(vite + vue3 + vue router + pinia + element plus))
  • (五)Python 垃圾回收机制
  • .NET Compact Framework 多线程环境下的UI异步刷新
  • .NET的微型Web框架 Nancy
  • .NET简谈设计模式之(单件模式)
  • .net利用SQLBulkCopy进行数据库之间的大批量数据传递
  • .NET与 java通用的3DES加密解密方法
  • .sdf和.msp文件读取
  • [ C++ ] STL---string类的使用指南
  • [ 代码审计篇 ] 代码审计案例详解(一) SQL注入代码审计案例
  • [.NET 即时通信SignalR] 认识SignalR (一)
  • []Telit UC864E 拨号上网
  • [20161101]rman备份与数据文件变化7.txt
  • [2018][note]用于超快偏振开关和动态光束分裂的all-optical有源THz超表——
  • [Angular] 笔记 18:Angular Router
  • [ASP]青辰网络考试管理系统NES X3.5
  • [C#C++]类CLASS
  • [C/C++] C/C++中数字与字符串之间的转换
  • [C++]:for循环for(int num : nums)