#Beats,KTT#洛谷 6792 [SNOI2020] 区间和

题目

区间取max和区间最大子段和


分析

区间取max得用 Beats 维护区间最小值和次小值,那区间最大子段和呢

Beats实际上是对这个区间里最小值批量增加,那么关于这个增加的量实际上是一个一次函数,斜率是当前方案包含的最小值的个数,

那就能交给 Beats 来维护最大子段和所需要的 lmax 和 rmax 以及最终的答案,都能通过一次函数来表示,

同时要满足变化量不超过临界点和介于最大值与次小值的限制才打标记否则继续递归。

最大的问题是 pushup,此时一次函数的系数只能当前的来自最小值,所以如果子节点不是最小值,pushup的时候就只保留截距再合并。


代码

#include <iostream>
#include <algorithm>
using namespace std;
typedef long long lll; const lll inf=1e18;
const int N=100011; lll a[N]; int n,Q;
struct rec{lll sum,lmax,rmax,w;};
struct Segment_Tree{
	rec K[N<<2],B[N<<2]; lll mn[N<<2],semn[N<<2],bound[N<<2];
	void pmax(lll k1,lll b1,lll k2,lll b2,lll &k,lll &b,lll &bound){
		if (b1<b2||(b1==b2&&k1<k2)) swap(k1,k2),swap(b1,b2);
		k=k1,b=b1;
		if (k1<k2) bound=min(bound,(b1-b2)/(k2-k1));
	}
	rec pup(rec x,rec y){
		return (rec){x.sum+y.sum,max(x.lmax,x.sum+y.lmax),max(y.rmax,x.rmax+y.sum),max(max(x.w,y.w),x.rmax+y.lmax)};
	}
	void pup(int k){
		rec KL=K[k<<1],KR=K[k<<1|1];
		if (mn[k<<1]==mn[k<<1|1]) mn[k]=mn[k<<1],semn[k]=min(semn[k<<1],semn[k<<1|1]),bound[k]=min(bound[k<<1],bound[k<<1|1]);
		else if (mn[k<<1]<mn[k<<1|1]) mn[k]=mn[k<<1],semn[k]=min(semn[k<<1],mn[k<<1|1]),KR=(rec){0,0,0,0},bound[k]=bound[k<<1];
			else mn[k]=mn[k<<1|1],semn[k]=min(mn[k<<1],semn[k<<1|1]),KL=(rec){0,0,0,0},bound[k]=bound[k<<1|1];
		K[k].sum=KL.sum+KR.sum,B[k].sum=B[k<<1].sum+B[k<<1|1].sum;
		pmax(KL.lmax,B[k<<1].lmax,KL.sum+KR.lmax,B[k<<1].sum+B[k<<1|1].lmax,K[k].lmax,B[k].lmax,bound[k]);
		pmax(KR.rmax,B[k<<1|1].rmax,KL.rmax+KR.sum,B[k<<1].rmax+B[k<<1|1].sum,K[k].rmax,B[k].rmax,bound[k]);
		pmax(KL.w,B[k<<1].w,KR.w,B[k<<1|1].w,K[k].w,B[k].w,bound[k]);
		pmax(K[k].w,B[k].w,KL.rmax+KR.lmax,B[k<<1].rmax+B[k<<1|1].lmax,K[k].w,B[k].w,bound[k]);
	}
	void ptag(int k,lll z){
		mn[k]+=z;
		B[k].sum+=K[k].sum*z,B[k].lmax+=K[k].lmax*z,
		B[k].rmax+=K[k].rmax*z,B[k].w+=K[k].w*z;
		if (bound[k]!=inf) bound[k]-=z;
	}
	void pdown(int k){
		if (mn[k<<1]<mn[k]) ptag(k<<1,mn[k]-mn[k<<1]);
		if (mn[k<<1|1]<mn[k]) ptag(k<<1|1,mn[k]-mn[k<<1|1]);
	}
	void build(int k,int l,int r){
		if (l==r){
			mn[k]=a[l],semn[k]=inf,bound[k]=inf;
			K[k]=(rec){1,1,1,1},B[k]=(rec){a[l],a[l],a[l],a[l]};
			return;
		}
		int mid=(l+r)>>1;
		build(k<<1,l,mid);
		build(k<<1|1,mid+1,r);
		pup(k);
	}
	void update(int k,int l,int r,int x,int y,lll z){
		if (z<=mn[k]) return;
		if (l==x&&r==y&&z<semn[k]&&z-mn[k]<=bound[k]){
			ptag(k,z-mn[k]);
			return;
		}
		int mid=(l+r)>>1;
		pdown(k);
		if (y<=mid) update(k<<1,l,mid,x,y,z);
		    else if (x>mid) update(k<<1|1,mid+1,r,x,y,z);
		        else update(k<<1,l,mid,x,mid,z),update(k<<1|1,mid+1,r,mid+1,y,z);
		pup(k);
	}
	rec query(int k,int l,int r,int x,int y){
		if (l==x&&r==y) return B[k];
		int mid=(l+r)>>1;
		pdown(k);
		if (y<=mid) return query(k<<1,l,mid,x,y);
		    else if (x>mid) return query(k<<1|1,mid+1,r,x,y);
		        else return pup(query(k<<1,l,mid,x,mid),query(k<<1|1,mid+1,r,mid+1,y));
	}
}Tre;
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>n>>Q;
	for (int i=1;i<=n;++i) cin>>a[i];
	Tre.build(1,1,n);
	for (;Q;--Q){
		int opt,l,r; cin>>opt>>l>>r;
		if (!opt){
			lll x; cin>>x;
			Tre.update(1,1,n,l,r,x);
		}
		else cout<<max(0ll,Tre.query(1,1,n,l,r).w)<<'\n';
	}
	return 0;
}
posted @ 2026-09-30 17:21  lemondinosaur  阅读(13)  评论(0)    收藏  举报