虽然@pkacprzak 的回答很好地描述了解决方案,但有些人可能更喜欢代码示例。
#include <iostream>
#define ll long long
using namespace std;
const int N=1<<17; // big power of 2 that fits your data
int n,k;
struct P {ll l, r, ts, bs;}; // left, right, totalsum, bestsum
P p[2*N];
ll maxf(ll a,ll b,ll c) {return max(a,max(b,c));}
P combine(P &cl,P &cr) {
P node;
node.ts = cl.ts + cr.ts;
node.l = maxf(cl.l, cl.ts, cl.ts + cr.l);
node.r = maxf(cr.r, cr.ts, cr.ts + cl.r);
node.bs = maxf(cl.bs, cr.bs, cl.r + cr.l);
return node;
}
void change(int k, ll x) {
k += N;
p[k].l = p[k].r = p[k].ts = p[k].bs = x;
for (k /= 2; k >= 1; k /= 2) {
p[k] = combine(p[2*k], p[2*k+1]);
}
}
要在分段树中添加/更改值,请使用change(k, x)(每次调用O(log(n))),其中 k 是位置,x 是值。每次调用change 后,可以从p[1].bs(树的顶部)读取最大子数组的总和。
如果您还需要找到子数组的确切索引,您可以在O(log(n)) 中进行递归自上而下查询,或使用迭代查询对O(log^2(n)) 进行二分搜索。
编辑:如果我们对给定子数组的最大子数组感兴趣,最好构建一个递归自顶向下查询。见:
https://www.quora.com/How-do-I-calculate-the-maximum-sub-segment-sum-in-a-segment-tree
总结一下,分段树可以处理这个问题改变数据和改变我们感兴趣的范围。