吉司机线段树
区间最值与区间历史最值
以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) 收藏 举报