适用于线段树、平衡树等树形结构。
一.区间修改,区间求和(求最值)
二.最大连续子序列
这里有一种类似于 \(DP\) 的方法。
对于一个节点 \(Rt\),我们需要维护四个值。
- \(sum\) : 此区间的总和。
- \(lmx\) : 此区间从左边开头的最大连续子序列。
- \(rmx\) : 此区间从右边开头的最大连续子序列。
- \(mx\) : 此区间的最大连续子序列。
想想怎么从两个儿子更改父亲节点的值。
如下图。
备注:① 代表 \(Rt\) 左儿子的 \(lmx\),② 代表 \(Rt\) 左儿子的 \(rmx\),⑤ 代表 \(Rt\) 左儿子的 \(sum\)。③、④、⑥ 同理。
1. \(Rt\) 的 \(sum\)。
很简单,左右儿子 \(sum\) 的和加上此节点的值即可。
code :
rt->sum = rt->ch[0]->sum + rt->ch[1]->sum + rt->val;
2. \(Rt\) 的 \(lmx\) 。
首先,合并左右儿子的区间后,\(Rt\) 的 \(lmx\) 可以为左儿子的 \(lmx\),即 ① 这一段。
其次,\(Rt\) 的 \(lmx\) 也可以由左儿子的总和、此节点的值与右儿子的 \(lmx\) 的和,即 ⑤ 与 ③ 这两段的和。
两者取最大即可。
code :
rt->lmx = max(rt->ch[0]->lmx, rt->ch[0]->sum + rt->ch[1]->lmx + rt->val);
3. \(Rt\) 的 \(rmx\) 。
与 \(lmx\) 类似的。
首先,\(Rt\) 的 \(rmx\) 可以为左儿子的 \(rmx\),即 ④ 这一段。
其次,\(Rt\) 的 \(rmx\) 也可以由右儿子的总和、此节点的值与左儿子的 \(rmx\) 的和,即 ⑥ 与 ② 这两段的和。
同样取较大者。
code :
rt->rmx = max(rt->ch[1]->rmx, rt->ch[1]->sum + rt->ch[0]->rmx + rt->val);
4. \(Rt\) 的 \(mx\)
最后,\(Rt\) 的 \(mx\) 有三种取值。
- \(Rt\) 左儿子的 \(mx\)。
- \(Rt\) 右儿子的 \(mx\)。
- \(Rt\) 左儿子的 \(rmx\)、此节点的值与右儿子的 \(lmx\) 之和,即 ② + ③。
code :
rt->mx = max({rt->ch[0]->mx, rt->ch[1]->mx, rt->ch[0]->rmx + rt->ch[1]->lmx + rt->val});
最后代码如下:
Code :
inline void pushup(node* &rt) {if (rt == NIL) return ;rt->siz = rt->ch[0]->siz + rt->ch[1]->siz + 1;rt->sum = rt->ch[0]->sum + rt->ch[1]->sum + rt->val;rt->lmx = max(rt->ch[0]->lmx, rt->ch[0]->sum + rt->ch[1]->lmx + rt->val);rt->rmx = max(rt->ch[1]->rmx, rt->ch[1]->sum + rt->ch[0]->rmx + rt->val);rt->mx = max({rt->ch[0]->mx, rt->ch[1]->mx, rt->ch[0]->rmx + rt->ch[1]->lmx + rt->val});
}