洛谷 P4513 小白逛公园
题意
单点修改 , 区间查询最大连续子段和
思路
有区间操作肯定是线段树之类的东西 , 然后考虑最长区间的可能 , 因为最终的结果状态必然是左右两个子树推出的 , 自然考虑从中间开始划分
如果最长段都在左侧 , 那就是左侧区间最长值推出该层的 ; 右侧同理
因此首先要维护一个区间最大和连续子序列
然后也可能是左侧的右部分和右侧的左部分的结合
而且 , 稍微想一下 , 必然是左侧的最大右部分和右侧最大左部分
我们在考虑某个值时 , 必然是大区间小区间一起考虑的 , 既要考虑如何根据左右侧最大部分获得当前最大值 , 也要考虑如何获得当前层的左右最大区间
如何获得呢? 这个时候我们发现 , 需要区间和
比如左侧区间最大值为左儿子的左侧区间最大值或者是左儿子的区间和再加上右儿子的左侧最大值
因为只考虑左侧 , 已经有了左儿子的左侧区间最大值
只有当出现右儿子数据时 , 大区间的左侧最大值才可能变化
且必然为到右儿子的左侧最大值那里
这个时候接着想 , 那么如何获取大区间的区间和呢?
这个就很简单了 , 把左右侧儿子的区间和加起来就好了 , 没有引入新的未知量
所以总体来说就是维护一棵 \(lmax\) , \(rmax\) , \(sum\) , \(ans\) 的线段树!
代码
#include<bits/stdc++.h>
using namespace std;
inline int read() {
int ans = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-')f = -1;
ch = getchar();
}
while (ch <= '9' && ch >= '0') {
ans = ans * 10 + ch - '0';
ch = getchar();
}
return ans * f;
}
const int N = 5e5+10;
int a[N];
int n,m;
struct Node {
int l,r,ans,lm,rm,sum;
};
Node tr[2000001];
void push_up(int p) {
tr[p].ans = max(tr[p*2].ans,tr[p*2+1].ans);
tr[p].ans = max(tr[p].ans,tr[p*2].rm + tr[p*2+1].lm);
tr[p].lm = max(tr[p*2].lm,tr[p*2].sum + tr[p*2+1].lm);
tr[p].rm = max(tr[p*2+1].rm, tr[p*2+1].sum + tr[p*2].rm);
tr[p].sum = tr[p*2].sum + tr[p*2+1].sum;
}
void build(int p,int l,int r) {
tr[p] = {l,r,a[l],a[l],a[l],a[l]};
if (l==r)
return;
int m = l + r>>1;
build(p*2,l,m);
build(p*2+1,m+1,r);
push_up(p);
}
void add(int p,int pos,int k) {
if (tr[p].l == tr[p].r) {
tr[p].ans = k;
tr[p].lm = k;
tr[p].rm = k;
tr[p].sum = k;
return ;
}
int mid = tr[p].l + tr[p].r >>1;
if (pos <= mid)
add(p*2,pos,k);
else {
add(p*2+1,pos,k);
}
push_up(p);
}
Node q(int p,int l,int r) {
if (tr[p].l >= l && tr[p].r <= r) {
return tr[p];
}
int mid = tr[p].l + tr[p].r >>1;
if (r <=mid) {
return q(p*2,l,r);
}
if (l> mid) {
return q(p*2+1,l,r);
}
Node t;
auto a = q(p*2,l,r), b= q(p*2+1,l,r);
//t.l = a.l,t.r = b.r;这句可以不写
t.lm = max(a.lm,a.sum + b.lm);
t.rm = max(b.rm,b.sum + a.rm);
t.sum = a.sum + b.sum;
t.ans = max(a.rm + b.lm,max(a.ans,b.ans));
return t;
}
int main() {
n = read(),m=read();
for (int i = 1; i<= n; i++) {
a[i] =read();
}
build(1,1,n);
for (int i = 1,op,a,b,p,s; i<= m; i++) {
op =read();
if (op == 1) {
a = read() , b=read();
if (a > b)
swap(a,b);
cout<<q(1,a,b).ans<<"\n";
}
else {
p =read(), s= read();
add(1,p,s);
}
}
return 0;
}

浙公网安备 33010602011771号