吉司机线段树
一、区间历史最值
以区间历史最大值为例。首先,相应地,设
void push_up(int u){
p[u].w=p[u<<1].w+p[u<<1|1].w;
p[u].maxa=max(p[u<<1].maxa,p[u<<1|1].maxa);
p[u].maxb=max(p[u<<1].maxb,p[u<<1|1].maxb);
}
void push_down(int u){//push_down时,注意先下传maxb,tag2,后下传maxa,tag1
p[u<<1].w+=(p[u<<1].r-p[u<<1].l+1)*p[u].tag1;
p[u<<1|1].w+=(p[u<<1|1].r-p[u<<1|1].l+1)*p[u].tag1;
p[u<<1].maxb=max(p[u<<1].maxb,p[u<<1].maxa+p[u].tag2);
p[u<<1|1].maxb=max(p[u<<1|1].maxb,p[u<<1|1].maxa+p[u].tag2);
p[u<<1].tag2=max(p[u<<1].tag2,p[u<<1].tag1+p[u].tag2);
p[u<<1|1].tag2=max(p[u<<1|1].tag2,p[u<<1|1].tag1+p[u].tag2);
p[u<<1].maxa+=p[u].tag1;
p[u<<1|1].maxa+=p[u].tag1;
p[u<<1].tag1+=p[u].tag1;
p[u<<1|1].tag1+=p[u].tag1;
p[u].tag1=p[u].tag2=0;
}
void build(int u,int l,int r){
p[u].l=l;p[u].r=r;
if(l==r){
p[u].w=p[u].maxa=p[u].maxb=a[l];
return ;
}
int mid=(l+r)>>1;
build(u<<1,l,mid);build(u<<1|1,mid+1,r);
push_up(u);
}
void add(int u,int l,int r,int w){
if(p[u].l>=l&&p[u].r<=r){
p[u].w+=(p[u].r-p[u].l+1)*w;
p[u].tag1+=w;
p[u].maxa+=w;
p[u].tag2=max(p[u].tag2,p[u].tag1);
p[u].maxb=max(p[u].maxb,p[u].maxa);
return ;
}
push_down(u);
int mid=(p[u].l+p[u].r)>>1;
if(mid>=l)
add(u<<1,l,r,w);
if(mid<r)
add(u<<1|1,l,r,w);
push_up(u);
}
int ask(int u,int l,int r,int opt){
if(p[u].l>=l&&p[u].r<=r){
if(opt==1) return p[u].w;
else if(opt==2) return p[u].maxa;
else return p[u].maxb;
}
push_down(u);
int re=0,maxx=-1e18,mid=(p[u].l+p[u].r)>>1;
if(mid>=l){
if(opt==1) re+=ask(u<<1,l,r,opt);
else maxx=max(maxx,ask(u<<1,l,r,opt));
}
if(mid<r){
if(opt==1) re+=ask(u<<1|1,l,r,opt);
else maxx=max(maxx,ask(u<<1|1,l,r,opt));
}
if(opt==1) return re;
else return maxx;
}
区间最值操作
以区间最小值操作,即把区间的所有数变成
此外,可以发现,该操作会导致区间最大值的
设
void push_up(int u){
p[u].w=p[u<<1].w+p[u<<1|1].w;
p[u].maxa=max(p[u<<1].maxa,p[u<<1|1].maxa);
p[u].maxb=max(p[u<<1].maxb,p[u<<1|1].maxb);
p[u].max2=max(p[u<<1].max2,p[u<<1|1].max2);
p[u].cnt=0;
if(p[u].maxa==p[u<<1].maxa)
p[u].cnt+=p[u<<1].cnt;
else
p[u].max2=max(p[u].max2,p[u<<1].maxa);
if(p[u].maxa==p[u<<1|1].maxa)
p[u].cnt+=p[u<<1|1].cnt;
else
p[u].max2=max(p[u].max2,p[u<<1|1].maxa);
}
void mktag(int u,int k1,int k2,int k3,int k4){
p[u].maxb=max(p[u].maxb,p[u].maxa+k3);
p[u].maxa+=k1;
if(p[u].max2!=-1e18)
p[u].max2+=k2;
p[u].w+=p[u].cnt*k1+(p[u].r-p[u].l+1-p[u].cnt)*k2;
p[u].tag3=max(p[u].tag3,p[u].tag1+k3);
p[u].tag4=max(p[u].tag4,p[u].tag2+k4);
p[u].tag1+=k1;
p[u].tag2+=k2;
}
void push_down(int u){
int maxx=max(p[u<<1].maxa,p[u<<1|1].maxa);
if(p[u<<1].maxa==maxx)
mktag(u<<1,p[u].tag1,p[u].tag2,p[u].tag3,p[u].tag4);
else
mktag(u<<1,p[u].tag2,p[u].tag2,p[u].tag4,p[u].tag4);
if(p[u<<1|1].maxa==maxx)
mktag(u<<1|1,p[u].tag1,p[u].tag2,p[u].tag3,p[u].tag4);
else
mktag(u<<1|1,p[u].tag2,p[u].tag2,p[u].tag4,p[u].tag4);
p[u].tag1=p[u].tag2=p[u].tag3=p[u].tag4=0;
}
void build(int u,int l,int r){
p[u].l=l;p[u].r=r;
if(l==r){
p[u].w=p[u].maxa=p[u].maxb=a[l];
p[u].cnt=1;
p[u].max2=-1e18;
return ;
}
int mid=(l+r)>>1;
build(u<<1,l,mid);build(u<<1|1,mid+1,r);
push_up(u);
}
void add(int u,int l,int r,int w){
if(p[u].l>=l&&p[u].r<=r){
mktag(u,w,w,w,w);
return ;
}
push_down(u);
int mid=(p[u].l+p[u].r)>>1;
if(mid>=l)
add(u<<1,l,r,w);
if(mid<r)
add(u<<1|1,l,r,w);
push_up(u);
}
void minn(int u,int l,int r,int w){
if(p[u].maxa<=w)
return ;
if(p[u].l>=l&&p[u].r<=r&&p[u].max2<w){
mktag(u,w-p[u].maxa,0,0,0);
return ;
}
push_down(u);
int mid=(p[u].l+p[u].r)>>1;
if(mid>=l)
minn(u<<1,l,r,w);
if(mid<r)
minn(u<<1|1,l,r,w);
push_up(u);
}
int ask(int u,int l,int r,int opt){
if(p[u].l>=l&&p[u].r<=r){
if(opt==1) return p[u].w;
else if(opt==2) return p[u].maxa;
return p[u].maxb;
}
push_down(u);
int mid=(p[u].l+p[u].r)>>1;
if(mid>=r)
return ask(u<<1,l,r,opt);
if(mid<l)
return ask(u<<1|1,l,r,opt);
if(opt==1)
return ask(u<<1,l,r,opt)+ask(u<<1|1,l,r,opt);
return max(ask(u<<1,l,r,opt),ask(u<<1|1,l,r,opt));
}
P4314 CPU 监控
题目要求维护一个支持区间推平,区间加,区间历史最值的线段树。
设
void mktag(int u,int k1,int k2,int k3,int k4,bool ok){
if(ok){//先加后赋
p[u].maxb=max(p[u].maxb,max(p[u].maxa+k2,k4));
p[u].maxa=k3;
if(p[u].ok){
p[u].tag4=max(p[u].tag4,max(p[u].tag3+k2,k4));
p[u].tag3=k3;
}
else{
p[u].tag2=max(p[u].tag2,p[u].tag1+k2);
p[u].tag1+=k1;
p[u].tag4=max(p[u].tag4,k4);
p[u].tag3=k3;
}
p[u].ok=1;
}
else{//只有加
p[u].maxb=max(p[u].maxb,p[u].maxa+k2);
p[u].maxa+=k1;
if(p[u].ok){
p[u].tag4=max(p[u].tag4,p[u].tag3+k2);
p[u].tag3+=k1;
}
else{
p[u].tag2=max(p[u].tag2,p[u].tag1+k2);
p[u].tag1+=k1;
}
}
}
void push_down(int u){
mktag(u<<1,p[u].tag1,p[u].tag2,p[u].tag3,p[u].tag4,p[u].ok);
mktag(u<<1|1,p[u].tag1,p[u].tag2,p[u].tag3,p[u].tag4,p[u].ok);
p[u].ok=p[u].tag1=p[u].tag2=p[u].tag3=0;
p[u].tag4=-1e18;
}
UOJ 169 元旦老人与数列
就是线段树三的板子,还没有区间和。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探