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

· 题目大意

要求维护一段长度为 \(n\) 的静态序列的区间最大子段和。

有 \(m\) 次询问,每次询问输出区间 \([L,R]\) 的最大子段和。

\(|a[i]| \leq 15007\),\(1 \leq m,n\leq5\times10^4\)

· 解题思路

首先想到如果用线段树的方法,那么预处理时间复杂度为\(O(n)\),总询问复杂度为\(O(m\cdot logn)\)。

当然这么想在这一题中没问题,但是如\(m\)的范围更大一点呢?比如\(1 \leq m \leq 1 \times10^7\)。这时候如果用线段树,很有可能会\(TLE\)。

既然没有修改,那么可以用\(ST\)表或者猫树这种 \(O(1)\) 查询的数据结构来完成这一题,于是笔者选择用猫树来完成这一题。

因为ST表太丑了(doge)

总时间复杂度为\(O(n\cdot logn+m)\)

· 代码实现

注释在代码里

#include <cstdio>
#include <algorithm>
#include <ctype.h>
#define reg register
using namespace std;
namespace io {
template<typename T>inline void read(T &x) {
char f=0,ch; x = 0;
while(!isdigit(ch=getchar())) f |= ch == '-';
while(isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar();
x = f? -x: x;
}
char ch[20];
template<typename T>inline void write(T x) {
(x < 0) && (x = -x, putchar('-'));
x || putchar('0');
reg int i=0;
while(x) ch[i++] = x % 10 ^ 48, x /= 10;
while(i) putchar(ch[--i]);
}
}//快读快写
#define rd io::read
#define wt io::write
const int maxN = 100020;
struct CatTree {
int pre, sum;
}t[maxN << 1][22];//维护一下区间前缀/后缀最大值,用于合并,然后维护一下区间子串最大值
int d[maxN << 1], pos[maxN << 1], a[maxN << 1];
int len=2, n, m;
void init(int, int, int);
int query(int, int);
int main() {
freopen("1.in", "r", stdin);
freopen("1.out", "w", stdout);
rd(n);
while(len < n) len <<= 1;
for(reg int i = 1; i <= n; ++i) rd(a[i]);
for(reg int i = 1; i <= len << 1; ++i) d[i] = d[i >> 1] + 1;
init(1, 1, len);
rd(m);
for(reg int i = 1, l, r; i <= m; ++i) {
rd(l); rd(r);
printf("%d\n", query(l, r));
}
return 0;
}
void init(int k, int l, int r) {
if (l==r) {pos[l]=k;return;}
int mid = l + r >> 1, pre , str;
pre = str = t[mid][d[k]].sum = t[mid][d[k]].pre = a[mid];
str = max(str, 0);
for(reg int i = mid - 1; i >= l; --i) {
pre += a[i], str += a[i];
t[i][d[k]].sum = max(t[i + 1][d[k]].sum, str);
t[i][d[k]].pre = max(t[i + 1][d[k]].pre, pre);str = max(str, 0);
}//处理左边区间子串最大值和左边区间后缀最大值。
pre = str = t[mid + 1][d[k]].sum = t[mid + 1][d[k]].pre = a[mid + 1];
str = max(str, 0);
for(reg int i = mid + 2; i <= r; ++i) {
pre += a[i], str += a[i];
t[i][d[k]].sum = max(t[i - 1][d[k]].sum, str);
t[i][d[k]].pre = max(t[i - 1][d[k]].pre, pre);str = max(str, 0);
}
init(k << 1, l, mid);init(k << 1 | 1, mid + 1, r);
}
int query(int l, int r) {
if (l == r) return a[l];
int fa = d[pos[l]] - d[pos[l] ^ pos[r]];//找到x和y的LCA
return max(max(t[l][fa].sum, t[r][fa].sum), t[l][fa].pre + t[r][fa].pre);
}
//最后答案就等于Max{左边的区间子串最大值,右边的区间子串最大值,左边的后缀最大值+右边的前缀最大值}

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

  1. 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]| ≤ ...

  2. SPOJ GSS1 Can you answer these queries I[线段树]

    Description You are given a sequence A[1], A[2], ..., A[N] . ( |A[i]| ≤ 15007 , 1 ≤ N ≤ 50000 ). A q ...

  3. SPOJ GSS1 Can you answer these queries I

    Time Limit: 115MS   Memory Limit: 1572864KB   64bit IO Format: %lld & %llu Description You are g ...

  4. SPOJ GSS1 Can you answer these queries I ——线段树

    [题目分析] 线段树裸题. 注意update的操作,写结构体里好方便. 嗯,没了. [代码] #include <cstdio> #include <cstring> #inc ...

  5. SPOJ GSS3 Can you answer these queries III[线段树]

    SPOJ - GSS3 Can you answer these queries III Description You are given a sequence A of N (N <= 50 ...

  6. GSS7 spoj 6779. Can you answer these queries VII 树链剖分+线段树

    GSS7Can you answer these queries VII 给出一棵树,树的节点有权值,有两种操作: 1.询问节点x,y的路径上最大子段和,可以为空 2.把节点x,y的路径上所有节点的权 ...

  7. 线段树 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).查询定义 ...

  8. GSS3 SPOJ 1716. Can you answer these queries III gss1的变形

    gss2调了一下午,至今还在wa... 我的做法是:对于询问按右区间排序,利用splay记录最右的位置.对于重复出现的,在splay中删掉之前出现的位置所在的节点,然后在splay中插入新的节点.对于 ...

  9. 题解【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 ...

随机推荐

  1. java并发编程基础——线程的创建

    一.基础概念 1.进程和线程 进程:每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销,一个进程包含1--n个线程.(进程是资源分配的最小单位) 线程:同一类线程共享代码和数据 ...

  2. deepin使用synergy鼠标越界软件实现和另一台windows系统共享鼠标

    1,搜索synergy就能找到很多安装和配置的博客文章. 2,我遇到的问题: 1,在linux(deepin)上安装1.8.8版本报出找不到依赖libssl.so.1.0.0的错误,导致无法成功启动软 ...

  3. linux U盘安装系统工具usb-creator-gtk

    linux平台下U盘安装linux系统的工具.它是ubuntu自带的工具,将建时将覆盖U盘中的所有内容.

  4. Leetcode:1008. 先序遍历构造二叉树

    Leetcode:1008. 先序遍历构造二叉树 Leetcode:1008. 先序遍历构造二叉树 思路 既然给了一个遍历结果让我们建树,那就是要需要前序中序建树咯~ 题目给的树是一颗BST树,说明中 ...

  5. gnome环境设置

    1.gnome的环境安装sudo apt-get install gnome2.选择gdm3 开机显示不正常:could not apply the stored configuration for ...

  6. Ubuntu Server连接Wi-Fi

    本文将介绍Ubuntu Server如何通过命令行使用wpa_supplicant连接Wi-Fi 环境 Ubuntu Server 20.04(64位) wpasupplicant 配置 1. 安装 ...

  7. xampp搭建开源项目iwebshop后,服务器重启后再启动xampp显示组件都启动ok,但是实际启动失败解决办法

    最近用xampp搭建了开源商城项目iwebshop,刚搭建完没问题,可是周一来因为服务器重启了,我再启动xampp,显示组件都启动ok了,但是用linux命令查看相关组件的进程时,发现实际没启动起来, ...

  8. SpringMVC中文乱码踩坑

    问题 使用SpringMVC在返回一个字符串时发生了中文乱码问题.produces属性无效 @RequestMapping(value = "/nihao", produces = ...

  9. []*T *[]T *[]*T 傻傻分不清楚

    前言 作为一个 Go 语言新手,看到一切"诡异"的代码都会感到好奇:比如我最近看到的几个方法:伪代码如下: func FindA() ([]*T,error) { } func F ...

  10. PHP 后台数组数据 传输给前台JS 使用

    一. PHP: $a = array('aaa','bbb'); $a= json_encode($a); JS: var a_json = {$a};   //此处a_json数组便可使用 二. H ...