zr day 2

线段树

1.小白逛公园

hh

由于讨论区间最大子段和有这几种情况:

  • 就在本区间
  • 这个区间和左边的区间相交
  • 这个区间和右边的区间相交

所以考虑线段树维护

  • 本区间最大子段和
  • 从左区间最大子段和
  • 从右区间最大子段和

这三个的最大值即为这个区间的答案

如何修改

考虑到是单点,直接修改即可,后续自会归并。

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;
}
posted @ 2024-07-18 15:12  PM_pro  阅读(13)  评论(0)    收藏  举报  来源