[题解] SPOJ GSS1 - Can you answer these queries I
[题解] 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的更多相关文章
- 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]| ≤ ...
- 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 ...
- SPOJ GSS1 Can you answer these queries I
Time Limit: 115MS Memory Limit: 1572864KB 64bit IO Format: %lld & %llu Description You are g ...
- SPOJ GSS1 Can you answer these queries I ——线段树
[题目分析] 线段树裸题. 注意update的操作,写结构体里好方便. 嗯,没了. [代码] #include <cstdio> #include <cstring> #inc ...
- 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 ...
- GSS7 spoj 6779. Can you answer these queries VII 树链剖分+线段树
GSS7Can you answer these queries VII 给出一棵树,树的节点有权值,有两种操作: 1.询问节点x,y的路径上最大子段和,可以为空 2.把节点x,y的路径上所有节点的权 ...
- 线段树 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).查询定义 ...
- GSS3 SPOJ 1716. Can you answer these queries III gss1的变形
gss2调了一下午,至今还在wa... 我的做法是:对于询问按右区间排序,利用splay记录最右的位置.对于重复出现的,在splay中删掉之前出现的位置所在的节点,然后在splay中插入新的节点.对于 ...
- 题解【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 ...
随机推荐
- C++第三十六篇 -- 为第一个驱动程序进行调试
工具是VMware12+Win10+VS2017+WDK1809 https://blog.csdn.net/qq_21763381/article/details/83242916 首先分清楚主计算 ...
- 八数码难题之 A* 算法
人生第一个A*算法-好激动-- 八数码难题--又称八数码水题,首先要理解一些东西: 1.状态可以转化成整数,比如状态: 1 2 3 4 5 6 7 8 0 可以转化成:123456780这个整数 2. ...
- AndroidStudio快捷键总结
本文总结一下最近常用的命令: 1.格式化代码:Ctrl+Alt+L[可能与电脑快捷键冲突,修改方法:在设置里点击Keymap 搜索:Reformat Code] 2.复制当前类:Ctrl+Shift+ ...
- 我说AOP(面向切面编程)--藏在苹果里的五角星
这只是一篇入门理解! 一直听说AOP的名字,却从未使用过,因为我不会.但--那只是曾经-- 先看官方解释:AOP(Aspect-Oriented Programming,面向切面的编程),它是可以通过 ...
- TypeScript学习笔记(四)装饰器
目录 一.装饰器的作用 二.类装饰器 1. 普通装饰器 为类扩展属性和方法 使用装饰器修改属性和重写方法 2. 装饰器工厂 三.属性装饰器 四.方法装饰器 使用方法装饰器对方法进行扩展 五.方法参数装 ...
- 墙裂推荐!2020Android阿里&腾讯&百度&字节&美团校招面试汇总
基本情况 2021届硕士生,Android开发岗 此文主要是2020年年初春招实习的面试和正式校招面试经验汇总,最终校招拿到了腾讯,百度,美团等offer 主要包括阿里4面,腾讯实习4面和校招4面,字 ...
- PHP构造函数__construct()
(!注意,__construct()前的"__"是两个"_",也就是"_ _") 在PHP5.0后的版本,允许开发者设定一个构造函数,来初始 ...
- 【学习笔记】Expression表达式目录树
Expression表达式目录树:一个能拼装能解析的数据结构,语法树. 一.手动拼装表达式目录树 示例1: /// <summary> /// 展示表达式树,协助用的 /// 编译lamb ...
- JavaScript学习01(js概述)
JavaScript概述 JavaScript历史 要了解JavaScript,我们首先要了解一下JavaScript的诞生. 在上个世纪的1995年,当时的网景公司正凭借其Navigator浏览器成 ...
- Mysql聚合函数count(1) sum(1)结果返回0和NULL
1.count(1) 返回为0 如果所查询的表或者where条件筛选后得到的结果集为空,则 count(1)返回为 0 如: select count(id) from test; select co ...