0%

[SP1043] GSS1 - Can you answer these queries I

题目

题目链接

题目大意: $m$ 次询问, 每次询问 $[l, r]$ 中的最大子段和. $1 \le n \le 50000$.

思路

可以猫树, 但是我不会写, 会写了补上.

考虑一个区间的最大子段和如何用线段树维护. 借用分治的思想, 最大的子段可能在中点以左, 中点以右, 或者穿过中点.

对于在中点左边和右边的情况很好更新, 现在考虑穿过中点的情况, 应为左边区间的最大后缀和加上右边区间的最大前缀和.

思考怎么维护最大前缀和和最大后缀和: 对于一段区间, 最大前缀和可能是左边区间的最大前缀和, 也有可能是左边区间的全部值加上右边区间的最大前缀和.

后缀和同理.

因此我们需要维护区间和, 最大前缀后缀和. 这道题没有修改操作, 还是很好写的.

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

template <class T>
inline void read(T &x) {
x = 0;
int f = 0;
char ch = getchar();
while (!isdigit(ch)) { f |= ch == '-'; ch = getchar(); }
while (isdigit(ch)) { x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar(); }
x = f ? -x : x;
return ;
}

typedef unsigned long long uLL;
typedef long long LL;

struct Node {
int l, r;
LL v, pre, suf, sum;
} t[200010];

int n, m, l, r;

inline int lson(int x) { return x << 1; }
inline int rson(int x) { return x << 1 | 1; }

void maintain(int x) {
t[x].sum = t[lson(x)].sum + t[rson(x)].sum;
t[x].pre = std::max(t[lson(x)].pre, t[lson(x)].sum + t[rson(x)].pre);
t[x].suf = std::max(t[rson(x)].suf, t[rson(x)].sum + t[lson(x)].suf);
t[x].v = std::max(t[lson(x)].v, std::max(t[rson(x)].v, t[lson(x)].suf + t[rson(x)].pre));
}

void buildTree(int x, int l, int r) {
t[x].l = l, t[x].r = r;
if (l == r) {
read(t[x].v);
t[x].pre = t[x].suf = t[x].sum = t[x].v;
return ;
}
int mid = (l + r) >> 1;
buildTree(lson(x), l, mid), buildTree(rson(x), mid + 1, r);
maintain(x);
}

Node query(int x, int l, int r) {
if (l <= t[x].l && r >= t[x].r) return t[x];
int mid = (t[x].l + t[x].r) >> 1;
if (l > mid) return query(rson(x), l, r);
if (r <= mid) return query(lson(x), l, r);
Node now, ls = query(lson(x), l, r), rs = query(rson(x), l, r);
now.sum = ls.sum + rs.sum;
now.pre = std::max(ls.pre, ls.sum + rs.pre);
now.suf = std::max(rs.suf, rs.sum + ls.suf);
now.v = std::max(ls.v, std::max(rs.v, ls.suf + rs.pre));
return now;
}

int main() {
read(n);
buildTree(1, 1, n);
read(m);
while (m--) {
read(l), read(r);
printf("%lld\n", query(1, l, r).v);
}
return 0;
}