Description
给定一个长度为 $n\ (n \leq 50000, \mid a_i \mid \leq 15007)$ 的整数序列,对于 $m\ (m \leq 50000)$ 个询问 $l,r\ (1 \leq l \leq r \leq n)$,求区间 $[l,r]$ 的最大子段和。
Source
Solution
前置知识:
线段树
如果用朴素的最大子段和算法,时间复杂度为 $O(nm)$,一定会超时。
很容易想到用数据结构来维护。
我们建立一棵线段树,对于区间 $x$,有以下定义:
$sum[x]$ 表示区间和;
$lsum[x]$ 表示以该区间左端点为起点的最大子段和;
$rsum[x]$ 表示以该区间右端点为起点的最大子段和;
$res[x]$ 表示该区间内的最大子段和。
与普通的线段树不同,这道题维护的信息很多,我们先来分析该题最重要的 $\mathrm{pushUp}$ 与 $\mathrm{query}$ 操作。
$\mathrm{pushUp}$ 操作
首先,是维护区间和,最基本的线段树操作,就不用多说了:
其次,假如我们知道一个区间的左右子区间信息,如何更新该区间的最大子段和?
很显然,答案可能为 左区间的最大子段和 或 右区间的最大子段和 。
除此之外,合并区间后,答案也有可能为 左区间的右起最大子段和 + 右区间的左起最大子段和,如上图。
由此我们可以得到代码:
那如何更新该区间的 左起最大子段和 和 右起最大子段和 呢?
区间左起最大子段和可以是 左区间的左起最大子段和 或 左区间的区间和 + 右区间的左起最大子段和,如上图。
右起最大子段和将上述操作反过来即可。
代码实现如下:
$\mathrm{query}$ 操作
当答案来自两个不同的区间时(如图),我们需要对这两个区间答案进行合并,并不只是取最大值那样简单。
我们还需要进行类似 $\mathrm{pushUp}$ 的操作,已知左右区间的答案,更新该区间答案。
函数的返回值有很多,所以用结构体式线段树实现更方便。
Code
1 |
|