[Acwing245]你能回答这个问题吗
一、题目
二、思路
用线段树求最大区间连续子段和
对于ans = max{左边区间的最大子段和,右边区间的最大子段和,跨越两个区间的最大子段和}
因此在写结构体时,节点应包含
sum:当前区间和
lmax:从左开始的最大子段和
rmax:从右开始的最大子段和
dat:整个区间的最大子段和
如果当前区间被要查询区间完全包含,返回当前区间的信息
如果要查询的区间只在当前区间的左区间,向左区间查询
如果要查询的区间只在当前区间的右区间,向右区间查询
其他情况,像pushup那样合并左右区间的查询结果,并返回
三、代码
#include<bits/stdc++.h>
using namespace std;
const int N = 5e5 + 10;
typedef long long ll;
#define u1 (u << 1)
#define u2 (u << 1 | 1)
struct Node{
int l, r;
int lmax, rmax;
int sum, dat;
}tr[N * 4];
void pushup(int u){
tr[u].sum = tr[u1].sum + tr[u2].sum;
tr[u].dat = max(max(tr[u1].dat, tr[u2].dat), tr[u1].rmax + tr[u2].lmax);
tr[u].lmax = max(tr[u1].lmax, tr[u1].sum + tr[u2].lmax);
tr[u].rmax = max(tr[u2].rmax, tr[u2].sum + tr[u1].rmax);
}
void build(int u, int l, int r){
tr[u].l = l;
tr[u].r = r;
if(l == r) {
int p;
cin >> p;
tr[u] = {l, r, p, p, p, p};
return;
}
int mid = l + r >> 1;
build(u1, l, mid), build(u2, mid + 1, r);
pushup(u);
}
Node query(int u, int l, int r){
if(tr[u].l >= l && tr[u].r <= r) return tr[u];
int mid = tr[u].l + tr[u].r >> 1;
if(r <= mid) return query(u1, l, r);
else if(l > mid) return query(u2, l, r);
else {
Node t1 = query(u1, l, mid), t2 = query(u2, mid + 1, r), t3;
t3.l = l, t3.r = r;
t3.sum = t1.sum + t2.sum;
t3.dat = max(max(t1.dat, t2.dat), t1.rmax + t2.lmax);
t3.lmax = max(t1.lmax, t2.lmax + t1.sum);
t3.rmax = max(t2.rmax, t1.rmax + t2.sum);
return t3;
}
}
void modify(int u, int x, int y){
if(tr[u].l == x && tr[u].r == x){
tr[u] = {x, x, y, y, y, y};
return;
}
int mid = tr[u].l + tr[u].r >> 1;
if(x <= mid) modify(u1, x, y);
if(x > mid) modify(u2, x, y);
pushup(u);
}
int main(){
int n, m;
cin >> n >> m;
build(1, 1, n);
int x, y;
while(m --){
int op;
cin >> op;
if(op == 1) {
cin >> x >> y;
if(x > y) swap(x, y);
cout << query(1, x, y).dat << endl;
}
else {
cin >> x >> y;
modify(1, x, y);
}
}
return 0;
}



浙公网安备 33010602011771号