P4314 题解
题意简述
给出长度为
- 求
的最大值。 - 求
的历史最大值。 - 将
全部加上给出的 。 - 将
全部改成给出的 。
题目分析
这个题和吉司机线段树在同一篇论文里面,感觉挺好玩就一起看了看。
看到这个题想必很多人都想直接设置两个懒标记
对于这一个问题,我们仍然可以采用懒标记解决。我们把着手点放在刚刚思路难以解决的,在相邻两次下传标记之间所更新的子结点的历史最大值的维护。不妨维护两次下传标记之间
代码实现
#include<bits/stdc++.h> using namespace std; int n,q,a[100010],l,r,x; char op; struct node { int l,r; int mx,mxx; int tag1,tag2,mxtag1,mxtag2; bool flag;//表示有无区间赋值操作 }tr[400010]; void rd(int &x) { int f=1; x=0; char c=getchar(); for(;c>'9'||c<'0';c=getchar()) if(c=='-') f=-1; for(;c<='9'&&c>='0';c=getchar()) x=(x<<3)+(x<<1)+c-'0'; x*=f; } void rd(char &c) { c=getchar(); for(;c!='Q'&&c!='A'&&c!='P'&&c!='C';c=getchar()); } void wt(int x) { if(x<0) { putchar('-'); x=-x; } if(x>=10) wt(x/10); putchar(x%10+'0'); } void pushup(int p) { tr[p].mx=max(tr[p<<1].mx,tr[p<<1|1].mx); tr[p].mxx=max(tr[p<<1].mxx,tr[p<<1|1].mxx); }//子结点更新父节点 void addtag1(int p,int tag,int mxtag)//区间加打标记 { tr[p].mxx=max(tr[p].mxx,tr[p].mx+mxtag); tr[p].mx+=tag; if(tr[p].flag)//如果有区间赋值就把这次加的值加到 tag2 上 { tr[p].mxtag2=max(tr[p].mxtag2,tr[p].tag2+mxtag);//更新 tag2 最大值 tr[p].tag2+=tag;//一定要先更新最大值再更新 tag2!!我因此调了好久…… } else { tr[p].mxtag1=max(tr[p].mxtag1,tr[p].tag1+mxtag);//没有区间赋值就直接加到 tag1 上。 tr[p].tag1+=tag; } } void addtag2(int p,int tag,int mxtag)//区间赋值打标记 { tr[p].tag2=tr[p].mx=tag;//直接赋值更新 tr[p].mxx=max(tr[p].mxx,mxtag);//更新历史最大值 if(tr[p].flag) tr[p].mxtag2=max(tr[p].mxtag2,mxtag); //更新最大 tag2 else { tr[p].flag=1; tr[p].mxtag2=mxtag; //最开始的最大标记直接赋值为打标记的值 } } void pushdown(int p) { addtag1(p<<1,tr[p].tag1,tr[p].mxtag1);//先下传更新区间加(区间赋值优先级更高,区间加完了之后也会被全部赋值) addtag1(p<<1|1,tr[p].tag1,tr[p].mxtag1); tr[p].tag1=tr[p].mxtag1=0;//清空标记 if(tr[p].flag) { addtag2(p<<1,tr[p].tag2,tr[p].mxtag2);//后下传更新区间赋值 addtag2(p<<1|1,tr[p].tag2,tr[p].mxtag2); tr[p].flag=0; tr[p].tag2=tr[p].mxtag2=0;//清空标记 } }//下传标记 void build(int p,int l,int r)//建树 { tr[p].l=l,tr[p].r=r; if(l==r) { tr[p].mx=tr[p].mxx=a[l];//最大值和历史最大值初始都是 a_l return; } int mid=l+r>>1; build(p<<1,l,mid);//左子结点 build(p<<1|1,mid+1,r);//右子结点 pushup(p); } void change1(int p,int l,int r,int x)//区间加 { if(tr[p].l>=l&&tr[p].r<=r) { addtag1(p,x,x);//修改的话历史最大值也取更改的值就好了 return; } pushdown(p); int mid=tr[p].l+tr[p].r>>1; if(mid>=l) change1(p<<1,l,r,x); if(mid<r) change1(p<<1|1,l,r,x); pushup(p); } void change2(int p,int l,int r,int x)//区间赋值 { if(tr[p].l>=l&&tr[p].r<=r) { addtag2(p,x,x);//同上 return; } pushdown(p); int mid=tr[p].l+tr[p].r>>1; if(mid>=l) change2(p<<1,l,r,x); if(mid<r) change2(p<<1|1,l,r,x); pushup(p); } int query1(int p,int l,int r)//查询最大值 { if(tr[p].l>=l&&tr[p].r<=r) return tr[p].mx; pushdown(p); int mid=tr[p].l+tr[p].r>>1,res=INT_MIN; if(mid>=l) res=query1(p<<1,l,r); if(mid<r) res=max(res,query1(p<<1|1,l,r)); return res; } int query2(int p,int l,int r)//查询历史最大值 { if(tr[p].l>=l&&tr[p].r<=r) return tr[p].mxx; pushdown(p); int mid=tr[p].l+tr[p].r>>1,res=INT_MIN; if(mid>=l) res=query2(p<<1,l,r); if(mid<r) res=max(res,query2(p<<1|1,l,r)); return res; } int main() { rd(n); for(int i=1;i<=n;i++) rd(a[i]); build(1,1,n); rd(q); while(q--) { rd(op),rd(l),rd(r); switch(op) { case 'Q': wt(query1(1,l,r)),putchar('\n'); break; case 'A': wt(query2(1,l,r)),putchar('\n'); break; case 'P': rd(x); change1(1,l,r,x); break; case 'C': rd(x); change2(1,l,r,x); } } return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端