题目链接:https://www.acwing.com/problem/content/246/
解题思路:
由于我们想要logn的时间复杂的情况下得到询问的答案,并且还要进行修改,为了不超时所以想到了使用线段树去求最大连续子序列和。
线段树本身是用到了分治的思想,那么如果用线段树,我们需要用道哪些东西才能得到正确的答案呢?
因为是线段树,所以我们每一个序列都需要分成2个子序列。
那么如果我们吧一个序列直接分成2个子序列,如果我们得到了左边子序列的最大值,也得到右边子序列的最大值,那么将子序列全部合起来的最大值就有3种情况:
1.左边子序列的最大值。
2.右边子序列的最大值。
3.中间某部分连接起来的数值
用线段树的话,关键就是我们如何去维护一些信息的道3这个答案;我们不妨这样想,我们给线段树种添加 lmax, rmax, maxx, sum;分别表示在这个区间内 从最左边点开始序列的最大值, 从最右边的点开始序列的最大值, 本序列的最大值, 整个区间之和。 假如我们得到了有这些信息的左右子节点,那么 1. max(左子树的lmax, 左子树的sum + 右子树的lmax) 2. max(右子树的rmax, 右子树的sum + 左子树的rmax) 3. max(左子树的maxx, 右子树的maxx, 左子树的rmax + 右子树的lmax)
AC代码:
#include <iostream>
#include <cstdio>
using namespace std;
const int maxn = 5e5 + 5;
struct SegmentTree {
int l, r;
int lmax, rmax, maxx;
int sum;
}t[maxn * 4];
int a[maxn];
int n, m;
inline void build(int p, int l, int r) {
t[p].l = l, t[p].r = r;
if(t[p].l == t[p].r) { t[p].lmax = t[p].rmax = t[p].maxx = t[p].sum = a[l]; return; }
int mid = (l + r) / 2;
build(p * 2, l, mid);
build(p * 2 + 1, mid + 1, r);
t[p].sum = t[p * 2].sum + t[p * 2 + 1].sum;
t[p].lmax = max(t[p * 2].lmax, t[p * 2].sum + t[p * 2 + 1].lmax);
t[p].rmax = max(t[p * 2 + 1].rmax, t[p * 2 + 1].sum + t[p * 2].rmax);
t[p].maxx = max(max(t[p * 2].maxx, t[p * 2 + 1].maxx), t[p * 2].rmax + t[p * 2 + 1].lmax);
}
inline void change(int p, int x, int y) {
if(t[p].l == t[p].r) { t[p].lmax = t[p].rmax = t[p].sum = t[p].maxx = y; return; }
int mid = (t[p].l + t[p].r) / 2;
if(x <= mid) change(p * 2, x, y);
else change(p * 2 + 1, x, y);
t[p].sum = t[p * 2].sum + t[p * 2 + 1].sum;
t[p].lmax = max(t[p * 2].lmax, t[p * 2].sum + t[p * 2 + 1].lmax);
t[p].rmax = max(t[p * 2 + 1].rmax, t[p * 2 + 1].sum + t[p * 2].rmax);
t[p].maxx = max(max(t[p * 2].maxx, t[p * 2 + 1].maxx), t[p * 2].rmax + t[p * 2 + 1].lmax);
}
inline SegmentTree ask(int p, int l, int r) {
if(l == t[p].l && r == t[p].r) return t[p];
int mid = (t[p].l + t[p].r) / 2;
if(mid >= r)
return ask(p * 2, l, r);
else if(mid < l)
return ask(p * 2 + 1, l, r);
else {
SegmentTree a, b, c;
a = ask(p * 2, l, mid);
b = ask(p * 2 + 1, mid + 1, r);
c.sum = a.sum + b.sum;
c.lmax = max(a.lmax, a.sum + b.lmax);
c.rmax = max(b.rmax, b.sum + a.rmax);
c.maxx = max(max(a.maxx, b.maxx), a.rmax + b.lmax);
return c;
}
}
int main(void) {
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i ++) scanf("%d", &a[i]);
build(1, 1, n);
while(m --) {
int op, x, y; scanf("%d%d%d", &op, &x, &y);
if(op == 1) {
if(x > y) swap(x, y);
printf("%d\n", ask(1, x, y).maxx);
}
else change(1, x, y);
}
return 0;
}
总结:对于有关数据结构和图论的题,如果遇到了困难,我个人觉得最好的理解方式就是暴力,即直接画图尝试一番。