zr day 2
线段树
1.小白逛公园
由于讨论区间最大子段和有这几种情况:
- 就在本区间
- 这个区间和左边的区间相交
- 这个区间和右边的区间相交
所以考虑线段树维护
- 本区间最大子段和
- 从左区间最大子段和
- 从右区间最大子段和
这三个的最大值即为这个区间的答案
如何修改
考虑到是单点,直接修改即可,后续自会归并。
Code
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+10;
struct node {
int l,r,suml,sumr,sumk,sum;
#define l(x) tr[x].l
#define r(x) tr[x].r
#define suml(x) tr[x].suml
#define sumr(x) tr[x].sumr
#define sumk(x) tr[x].sumk
#define sum(x) tr[x].sum
}tr[N*4];
int n,m,w[N];
void pushup(int x) {
sum(x)=sum(x*2)+sum(x*2+1);
suml(x)=max(suml(x*2),sum(x*2)+suml(x*2+1));
sumr(x)=max(sumr(x*2+1),sum(x*2+1)+sumr(x*2));
sumk(x)=max(max(sumk(x*2),sumk(x*2+1)),sumr(x*2)+suml(x*2+1));
}
void build(int x,int l,int r) {
l(x)=l,r(x)=r;
if(l==r) {
sumk(x)=suml(x)=sumr(x)=sum(x)=w[l];
return;
}
int mid=l+r>>1;
build(x*2,l,mid);build(x*2+1,mid+1,r);
pushup(x);
}
void change(int x,int pos,int k) {
int l=l(x),r=r(x);
if(l==pos&&r==pos) {
sumk(x)=suml(x)=sumr(x)=sum(x)=k;
return;
}
int mid=l+r>>1;
if(pos<=mid) change(x*2,pos,k);
if(pos>mid) change(x*2+1,pos,k);
pushup(x);
}
node qry(int x,int ll,int rr) {
int l=l(x),r=r(x);
if(l>=ll&&r<=rr) return tr[x];
int mid=l+r>>1,ans=-0x3f3f3f3f;
if(rr<=mid) return qry(x*2,ll,rr);
if(ll>mid) return qry(x*2+1,ll,rr);
node a,b=qry(x*2,ll,rr),c=qry(x*2+1,ll,rr);
a.suml=max(b.suml,b.sum+c.suml);
a.sumr=max(c.sumr,c.sum+b.sumr);
a.sumk=max(max(a.suml,a.sumr),b.sumr+c.suml);
return a;
}
signed main() {
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>w[i];
build(1,1,n);
while(m--) {
int x;
cin>>x;
if(x==1) {
int a,b;
cin>>a>>b;
if(a>b) swap(a,b);
cout<<qry(1,a,b).sumk<<endl;
}
else {
int a,b;
cin>>a>>b;
change(1,a,b);
}
}
return 0;
}

浙公网安备 33010602011771号