题目链接:
学习一番线段树的历史标记~
这道题就是区间加法,区间赋值,要询问区间最大值 和 区间历史最大值的最大值。
然后这种题就是在现有标记的基础上多弄一套标记,维护这个点出现过的最大的标记。然后下传标记的时候注意要先传历史标记再传现在的标记。
王队告诉我说,关于历史标记,可以理解成每个节点有过很多标记,可以看成每个节点都有一个标记队列。这样的话,现在的标记就是在维护这个队列的最后一个,历史标记就是这个队列的\(max\)。所以传标记的时候需要先下传历史标记。
一定要把各种标记想清楚了再写。
下面贴代码:
#include#include #include #include #include #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)#define INF (-2147483647)#define maxn 100010using namespace std;typedef long long llg;int n,m,L,R,_nm,_pm,z,_;int nmax[maxn<<2],nadd[maxn<<2],ncov[maxn<<2];//现在的标记int pmax[maxn<<2],padd[maxn<<2],pcov[maxn<<2];//历史标记int getint(){ int w=0;bool q=0; char c=getchar(); while((c>'9'||c<'0')&&c!='-') c=getchar(); if(c=='-') c=getchar(),q=1; while(c>='0'&&c<='9') w=w*10+c-'0',c=getchar(); return q?-w:w;}void update(int u){ nmax[u]=max(nmax[u<<1],nmax[u<<1|1]); pmax[u]=max(pmax[u<<1],pmax[u<<1|1]);}void pushdown(int u){ for(int i=0,v;i<2;i++){ v=u<<1|i; pmax[v]=max(pmax[v],nmax[v]+padd[u]); pmax[v]=max(pmax[v],pcov[u]); if(ncov[v]==INF) padd[v]=max(padd[v],nadd[v]+padd[u]); else pcov[v]=max(pcov[v],ncov[v]+padd[u]); if(nadd[u]){ nmax[v]+=nadd[u]; if(ncov[v]==INF) nadd[v]+=nadd[u]; else ncov[v]+=nadd[u]; } if(ncov[u]!=INF){ nmax[v]=ncov[u]; ncov[v]=ncov[u]; nadd[v]=0; pcov[v]=max(pcov[v],pcov[u]); } } padd[u]=nadd[u]=0,pcov[u]=ncov[u]=INF;}void build(int u,int l,int r){ pcov[u]=ncov[u]=INF; int lc=u<<1,lv=u<<1|1,mid=(l+r)>>1; if(l==r) nmax[u]=pmax[u]=getint(); else build(lc,l,mid),build(lv,mid+1,r),update(u);}void query(int u,int l,int r){ if(l!=r) pushdown(u); if(l>=L && r<=R) _nm=max(_nm,nmax[u]),_pm=max(_pm,pmax[u]); else{ int mid=(l+r)>>1; if(L<=mid) query(u<<1,l,mid); if(R>mid) query(u<<1|1,mid+1,r); }}void add(int u,int l,int r){ if(l!=r) pushdown(u); if(l>=L && r<=R) if(_) padd[u]=nadd[u]=z,pmax[u]=max(pmax[u],nmax[u]+=z); else pcov[u]=ncov[u]=z,pmax[u]=max(pmax[u],nmax[u]=z); else{ int mid=(l+r)>>1; if(L<=mid) add(u<<1,l,mid); if(R>mid) add(u<<1|1,mid+1,r); update(u); }}int main(){ File("a"); n=getint(),build(1,1,n); m=getint(); char c; while(m--){ c=getchar(); while(c!='A' && c!='Q' && c!='P' && c!='C') c=getchar(); L=getint(); R=getint(); if(c=='Q' || c=='A'){ _nm=_pm=INF; query(1,1,n); printf("%d\n",c=='Q'?_nm:_pm); } else{ z=getint(); _=c=='P'; add(1,1,n); } } return 0;}