题目大意:给出一个动态的区间,以及 m 次询问,每次询问给出一段区间 [l, r],要我们求出这段区间中 和最大的连续序列。
看到这种单点修改和区间查询的问题,我们一般会想到线段树来求解。
对于这道题来说,我们可以将最原始的线段树修改成如下的几个参数
struct tree{
int lmax; // 当前区间最大前缀和
int rmax; // 当前区间最大后缀和
int maxx; // 当前区间最大子段和
int sum; // 当前区间的和
}t[4 * maxn];
于是我们就可以像这样维护连续的子区间和了
void push_up(int rt){
t[rt].sum = t[rt << 1].sum + t[rt << 1 | 1].sum;
// 当前区间的和:左子树的和+右子树的和
t[rt].rmax = max(t[rt << 1 | 1].rmax, t[rt << 1 | 1].sum + t[rt << 1].rmax);
// 当前区间的最大后缀和:右子树的最大后缀和 or 右子树的和+左子树的最大后缀和
t[rt].lmax = max(t[rt << 1].lmax, t[rt << 1].sum + t[rt << 1 | 1].lmax);
// 当前区间的最大前缀和:左子树的最大前缀和 or 左子树的和+右子树的最大前缀和
t[rt].maxx = max(t[rt << 1].rmax + t[rt << 1 | 1].lmax, max(t[rt << 1].maxx, t[rt << 1 | 1].maxx));
// 当前区间的最大子段和:左子树的最大子段和 or 右子树的最大子段和 or 左子树的最大后缀和+右子树的最大前缀和
}
如果还是理解不了可以自己画图试试。
建树和修改的过程跟普通线段树没什么太大区别
void build(int rt, int l, int r){
if(l == r){
cin >> t[rt].maxx;
t[rt].lmax = t[rt].rmax = t[rt].sum = t[rt].maxx;
return;
}
int mid = l + r >> 1;
build(rt << 1, l, mid);
build(rt << 1 | 1, mid + 1, r);
push_up(rt);
}
void update(int rt, int l, int r, int x, int y){
if(l == r){
t[rt].lmax = t[rt].rmax = t[rt].maxx = t[rt].sum = y;
return ;
}
int mid = l + r >> 1;
if(mid >= x) update(rt << 1, l, mid, x, y);
else update(rt << 1 | 1, mid + 1, r, x, y);
push_up(rt);
}
询问的时候要特别注意,要做一次类似于 push_up 的操作寻找最优值,不能直接返回 max(t[rt << 1].maxx, t[k << 1 | 1].maxx),因为可能询问的区间不完全包含左儿子或右儿子的区间(若完全包含,则不用合并)。
tree query(int rt, int l, int r, int x, int y){
if(l >= x && r <= y) return t[rt]; // 区间完全覆盖,直接返回该节点
int mid = l + r >> 1;
if(y <= mid) return query(rt << 1, l, mid, x, y); // 只在左区间,直接查询左区间
else if(x > mid) return query(rt << 1 | 1, mid + 1, r, x, y); // 只在右区间,直接查询右区间
else{
tree res_l = query(rt << 1, l, mid, x, y);
tree res_r = query(rt << 1 | 1, mid + 1, r, x, y);
tree res;
// res_l记录左覆盖区间,res_r记录右覆盖区间,合并后得到res
// 用push_up同样的方式更新res
res.sum = res_l.sum + res_r.sum;
res.lmax = max(res_l.sum + res_r.lmax, res_l.lmax);
res.rmax = max(res_r.rmax, res_r.sum + res_l.rmax);
res.maxx = max(max(res_l.maxx, res_r.maxx), res_l.rmax + res_r.lmax);
return res;
}
}
最后整体代码如下
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn = 1001000;
int n, m;
int ans;
struct tree{
int lmax; // 当前区间最大前缀和
int rmax; // 当前区间最大后缀和
int maxx; // 当前区间最大子段和
int sum; // 当前区间的和
}t[4 * maxn];
void push_up(int rt){
t[rt].sum = t[rt << 1].sum + t[rt << 1 | 1].sum;
// 当前区间的和:左子树的和+右子树的和
t[rt].rmax = max(t[rt << 1 | 1].rmax, t[rt << 1 | 1].sum + t[rt << 1].rmax);
// 当前区间的最大后缀和:右子树的最大后缀和 or 右子树的和+左子树的最大后缀和
t[rt].lmax = max(t[rt << 1].lmax, t[rt << 1].sum + t[rt << 1 | 1].lmax);
// 当前区间的最大前缀和:左子树的最大前缀和 or 左子树的和+右子树的最大前缀和
t[rt].maxx = max(t[rt << 1].rmax + t[rt << 1 | 1].lmax, max(t[rt << 1].maxx, t[rt << 1 | 1].maxx));
// 当前区间的最大子段和:左子树的最大子段和 or 右子树的最大子段和 or 左子树的最大后缀和+右子树的最大前缀和
}
void build(int rt, int l, int r){
if(l == r){
cin >> t[rt].maxx;
t[rt].lmax = t[rt].rmax = t[rt].sum = t[rt].maxx;
return;
}
int mid = l + r >> 1;
build(rt << 1, l, mid);
build(rt << 1 | 1, mid + 1, r);
push_up(rt);
}
void update(int rt, int l, int r, int x, int y){
if(l == r){
t[rt].lmax = t[rt].rmax = t[rt].maxx = t[rt].sum = y;
return ;
}
int mid = l + r >> 1;
if(mid >= x) update(rt << 1, l, mid, x, y);
else update(rt << 1 | 1, mid + 1, r, x, y);
push_up(rt);
}
tree query(int rt, int l, int r, int x, int y){
if(l >= x && r <= y) return t[rt]; // 区间完全覆盖,直接返回该节点
int mid = l + r >> 1;
if(y <= mid) return query(rt << 1, l, mid, x, y); // 只在左区间,直接查询左区间
else if(x > mid) return query(rt << 1 | 1, mid + 1, r, x, y); // 只在右区间,直接查询右区间
else{
tree res_l = query(rt << 1, l, mid, x, y);
tree res_r = query(rt << 1 | 1, mid + 1, r, x, y);
tree res;
// res_l记录左覆盖区间,res_r记录右覆盖区间,合并后得到res
// 用push_up同样的方式更新res
res.sum = res_l.sum + res_r.sum;
res.lmax = max(res_l.sum + res_r.lmax, res_l.lmax);
res.rmax = max(res_r.rmax, res_r.sum + res_l.rmax);
res.maxx = max(max(res_l.maxx, res_r.maxx), res_l.rmax + res_r.lmax);
return res;
}
}
signed main(){
cin >> n >> m;
build(1, 1, n);
int opt, x, y;
while(m--){
cin >> opt >> x >> y;
if(opt == 1){
if(x > y) swap(x, y);
tree ans = query(1, 1, n, x, y);
cout << ans.maxx << '\n';
}
else update(1, 1, n, x, y);
}
system("pause");
}