Pearblossom

吉司机线段树

区间最值与区间历史最值

P4314 CPU 监控为例,将线段树分为 \(info\)\(tag\) 两类,要求维护历史最值

对于 \(info\) ,要维护 \(mx\)\(hmx\) 对于 \(tag\) ,要维护 \(add,hadd,c,hc\) 分别为区间加的标记,区间加的最大标记,区间覆盖标记,区间覆盖的最大标记

  • 对于 \(D+D\) 类,直接去 \(max\) 即可

  • 对于 \(M+M\) 类,对覆盖标记的有无分类讨论即可,具体的:对于没一个修改可以分为两个阶段,只有加标记的阶段一和覆盖标记的阶段二,历史最值要么是阶段一的最大加标记,要么是阶段二的最大覆盖标记,覆盖后的加可以直接合并为一个覆盖操作

  • 对于 \(D+M\) 类,最大值就直接更新,历史最值就结合最大标记更新即可

对于区间取 \(min\) 操作,需要额外维护区间的严格次大值 \(smx\) ,在更新时对 \(x\) 与最大值和次大值的关系分讨:

  • \(mx \le x\) ,则该修改对当前区间无影响,直接返回

  • \(smx < x < mx\) ,则该修改只会使最大值改变 \(x-mx\) ,将最大值的修改标记更新即可,

  • \(smx \le x\) ,则该修改可能影响到的数无法直接更新,就直接递归修改。(这里等于的情况不能归为情况 \(2\) ,因为无法快速更新严格次大值)。

在下传标记时,不能直接让左右儿子加上 \(tag\) ,因为最大值的标记只针对该区间的最大值,而左儿子或右儿子不一定存在该最大值,所以只对存在最大值的下传最大值的标记,不存在的就下传一般的标记

P4314 CPU 监控


#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=5e6+10,inf=1e15;
int a[N];
struct info{
	int mx,hmx;
	info operator +(const info f) const{
		return info{max(mx,f.mx),max(hmx,f.hmx)};
	}
};
struct Tag{
	int add,ha,c,hc;
	void clear(){add=ha=0;c=hc=-inf;}
	Tag operator +(const Tag f)const {
		Tag g;
		if(add==0&&ha==0&&c==-inf&&hc==-inf) return f;
		if(c==-inf) {
			g.add=add+f.add;
			g.ha=max(ha,add+f.ha);
			if(f.c==-inf) g.c=g.hc=-inf;
			else {
				g.add=0;
				g.c=f.c;
				g.hc=f.hc;
			}
			return g;
		}
		g.add=0;g.ha=ha;
		g.hc=max(hc,max(c+f.ha,f.hc));
		if(f.c==-inf) g.c=c+f.add;
		else g.c=f.c;
		return g;
	}
};
info mad[N];Tag tag[N];
info operator +(const info &a,const Tag &b) {
	info c;
	c.hmx=max(a.hmx,a.mx+b.ha);
	c.mx=a.mx+b.add;
	if(b.c!=-inf) {
		c.hmx=max(c.hmx,b.hc);
		c.mx=b.c;
	}
	return c;
}
void Down(int p,int l,int r) {
	Tag op=tag[p];
	tag[p].clear();
	if(l==r) return;
	tag[p<<1]=tag[p<<1]+op;
	mad[p<<1]=mad[p<<1]+op;
	tag[p<<1|1]=tag[p<<1|1]+op;
	mad[p<<1|1]=mad[p<<1|1]+op;
	return;
}
void Up(int p) {mad[p]=mad[p<<1]+mad[p<<1|1];}
void Change(int l,int r,int p,int tl,int tr,int x,int type) {
	//type==1 加 type==2 覆盖 
	if(tl<=l&&r<=tr) {
		Tag op;op.clear();
		if(type==1) op.add=op.ha=x;
		if(type==2) op.c=op.hc=x;
		tag[p]=tag[p]+op;
		mad[p]=mad[p]+op;
		return;
	}
	Down(p,l,r);
	int mid=(l+r)>>1;
	if(tl<=mid) Change(l,mid,p<<1,tl,tr,x,type);
	if(tr>mid)Change(mid+1,r,p<<1|1,tl,tr,x,type);
	Up(p);
	return;
}
int Query(int l,int r,int p,int tl,int tr,int type) {
	//type==1 最值 type==2 历史最值
	if(tl<=l&&r<=tr) {
		if(type==1) return mad[p].mx;
		return mad[p].hmx;
	}
	Down(p,l,r);
	int mid=(l+r)>>1,op=-inf;
	if(tl<=mid) op=max(op,Query(l,mid,p<<1,tl,tr,type));
	if(tr>mid)op=max(op,Query(mid+1,r,p<<1|1,tl,tr,type));
	return op;
}
void Build(int l,int r,int p) {
	if(l==r) {
		mad[p].mx=mad[p].hmx=a[l];
		tag[p].clear();
		return;
	}
	tag[p].clear();
	int mid=(l+r)>>1;
	Build(l,mid,p<<1);Build(mid+1,r,p<<1|1);
	Up(p);return;
}
signed main() {
	int n;cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i];
	Build(1,n,1);
	int E;cin>>E;
	while(E--) {
		char c;int x,y,z;
		cin>>c;
		if(c=='Q') {
			cin>>x>>y;
			cout<<Query(1,n,1,x,y,1)<<'\n';
		}
		if(c=='A') {
			cin>>x>>y;
			cout<<Query(1,n,1,x,y,2)<<'\n';
		}
		if(c=='P') {
			cin>>x>>y>>z;
			Change(1,n,1,x,y,z,1);
		}
		if(c=='C') {
			cin>>x>>y>>z;
			Change(1,n,1,x,y,z,2);
		}
	}
	return 0;
}

P6242 【模板】线段树 3


#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=5e6+100,inf=1e15;
int a[N],n,m;
struct info{
	int mx,smx,sum,hmx,cnt,scnt,len;
	info operator +(const info &f) const{
		info g;
		g.mx=max(mx,f.mx);
		g.sum=sum+f.sum;
		g.len=len+f.len;
		g.hmx=max(hmx,f.hmx);
		if(mx==f.mx) {
			g.cnt=cnt+f.cnt;
			g.smx=max(smx,f.smx);
			if(smx==f.smx) g.scnt=scnt+f.scnt;
			else if(g.smx==smx) g.scnt=scnt;
			else g.scnt=f.scnt;
		}
		else if(g.mx==mx) {
			g.cnt=cnt;
			g.smx=max(smx,f.mx);
			if(smx==f.mx) g.scnt=scnt+f.cnt;
			else if(g.smx==smx) g.scnt=scnt;
			else g.scnt=f.cnt;
		}
		else {
			g.cnt=f.cnt;
			g.smx=max(mx,f.smx);
			if(mx==f.smx) g.scnt=cnt+f.scnt;
			else if(g.smx==mx) g.scnt=cnt;
			else g.scnt=f.scnt;
		}
		return g;
	}
};
struct Tag{
	int add,hadd,mxadd,hmxadd;
	void clear(){add=hadd=mxadd=hmxadd=0;return;}
	Tag operator +(const Tag &f)const{
		Tag g;
		g.add=add+f.add;
		g.hadd=max(hadd,add+f.hadd);
		g.mxadd=mxadd+f.mxadd;
		g.hmxadd=max(hmxadd,mxadd+f.hmxadd);
		return g;
	}
};
info operator +(const info &a,const Tag &b) {
	info c;
	c.cnt=a.cnt;c.scnt=a.scnt;c.len=a.len;
	c.sum=a.sum+b.mxadd*a.cnt
	+b.add*(a.len-a.cnt);
	c.hmx=max(a.hmx
	,max(a.mx+b.hmxadd,a.smx+b.hadd));
	c.mx=a.mx+b.mxadd;
	c.smx=(a.scnt>0)?(a.smx+b.add):(-inf);
	if(c.mx<c.smx) swap(c.mx,c.smx);
	return c;
}
info mad[N];Tag tag[N];
void Up(int p){mad[p]=mad[p<<1]+mad[p<<1|1];}
void Down(int p,int l,int r) {
	Tag op=tag[p];tag[p].clear();
	if(l==r) return;
	//在下传时有最大值的下传最大值的修改标记,没有就下传正常标记
	if(mad[p<<1].mx<mad[p<<1|1].mx) {
		mad[p<<1|1]=mad[p<<1|1]+op;
		tag[p<<1|1]=tag[p<<1|1]+op;
		mad[p<<1]=mad[p<<1]+Tag{op.add,op.hadd,op.add,op.hadd};
		tag[p<<1]=tag[p<<1]+Tag{op.add,op.hadd,op.add,op.hadd};
	}
	else if(mad[p<<1].mx>mad[p<<1|1].mx) {
		mad[p<<1]=mad[p<<1]+op;
		tag[p<<1]=tag[p<<1]+op;
		mad[p<<1|1]=mad[p<<1|1]+Tag{op.add,op.hadd,op.add,op.hadd};
		tag[p<<1|1]=tag[p<<1|1]+Tag{op.add,op.hadd,op.add,op.hadd};
	} 
	else {
		mad[p<<1]=mad[p<<1]+op;
		tag[p<<1]=tag[p<<1]+op;
		mad[p<<1|1]=mad[p<<1|1]+op;
		tag[p<<1|1]=tag[p<<1|1]+op;
	}
	return;
}
void Add(int l,int r,int p,int tl,int tr,int k) {
	if(tl<=l&&r<=tr) {
		Tag op;op.clear();
		op.add=op.mxadd=op.hadd=op.hmxadd=k;
		tag[p]=tag[p]+op;mad[p]=mad[p]+op;
		return;
	}
	Down(p,l,r);int mid=(l+r)>>1;
	if(tl<=mid) Add(l,mid,p<<1,tl,tr,k);
	if(tr>mid)Add(mid+1,r,p<<1|1,tl,tr,k);
	Up(p);return;
}
void Min(int l,int r,int p,int tl,int tr,int k) {
	if(mad[p].mx<=k) return;
	if(l>r) return;
	int mid=(l+r)>>1;
	if(tl<=l&&r<=tr) {
		if(mad[p].smx<k&&k<mad[p].mx) {
			Tag op;op.clear();
			op.hmxadd=op.mxadd=k-mad[p].mx;
			tag[p]=tag[p]+op;
			mad[p]=mad[p]+op;
			return;
		}
		if(l!=r) {//对于叶子节点不递归 
			Down(p,l,r);
			Min(l,mid,p<<1,tl,tr,k);
			Min(mid+1,r,p<<1|1,tl,tr,k);
			Up(p);
			return;
		}
		return;
	}
	Down(p,l,r);
	if(tl<=mid) Min(l,mid,p<<1,tl,tr,k);
	if(tr>mid)Min(mid+1,r,p<<1|1,tl,tr,k);
	Up(p);return;
}
int Query(int l,int r,int p,int tl,int tr,int type) {
	//type==1 最值 type==2 历史最值 type==3 区间和 
	if(tl<=l&&r<=tr) {
		if(type==1) return mad[p].mx;
		if(type==2) return mad[p].hmx;
		return mad[p].sum;
	}
	Down(p,l,r);int mid=(l+r)>>1;
	if(type<=2) {
		int op=-inf;
		if(tl<=mid) op=max(op,Query(l,mid,p<<1,tl,tr,type));
		if(tr>mid)op=max(op,Query(mid+1,r,p<<1|1,tl,tr,type));
		return op;
	}
	int sum=0;
	if(tl<=mid) sum=sum+Query(l,mid,p<<1,tl,tr,type);
	if(tr>mid)sum=sum+Query(mid+1,r,p<<1|1,tl,tr,type);
	return sum;
}
void Build(int l,int r,int p) {
	tag[p].clear();
	if(l==r) {
		mad[p].mx=mad[p].sum=mad[p].hmx=a[l];
		mad[p].len=1;mad[p].cnt=1;mad[p].scnt=0;
		mad[p].smx=-inf;return;//次大值要赋值为负无穷 
	}
	int mid=(l+r)>>1;
	Build(l,mid,p<<1);Build(mid+1,r,p<<1|1);
	Up(p);
}
signed main() {
	cin>>n>>m;
	for(int i=1;i<=n;i++) cin>>a[i];
	int op,l,r,k,v;
	Build(1,n,1);while(m--) {
		cin>>op;
		if(op==1) {
			cin>>l>>r>>k;
			Add(1,n,1,l,r,k);
		}
		if(op==2) {
			cin>>l>>r>>k;
			Min(1,n,1,l,r,k);
		}
		if(op==3) {
			cin>>l>>r;
			cout<<Query(1,n,1,l,r,3)<<'\n';
		}
		if(op==4) {
			cin>>l>>r;
			cout<<Query(1,n,1,l,r,1)<<'\n';
		}
		if(op==5) {
			cin>>l>>r;
			cout<<Query(1,n,1,l,r,2)<<'\n';
		}
	}
	return 0;
}

posted on 2025-07-09 10:50  Pearblossom  阅读(19)  评论(0)    收藏  举报

导航