P4314 CPU 监控(区间历史最值)
Description
维护一个长度为 \(n\) 的序列 \(A\),初始所有位置都是 \(0\)。
\(Q\) 次操作:
Q X Y
:询问 \(A[X,Y]\) 的 $ \max$。A X Y
:询问 \(A[X,Y]\) 的历史 \(\max\)。P X Y Z
:\(A[X,Y]\) 全部加上 \(Z\)。C X Y Z
:\(A[X,Y]\) 全部变为 \(Z\)。
\(1\leq n,Q\leq 10^5\)。
Solution
由于需要维护历史最值,我们需要在线段树节点上用 lazy tag 刻画出一个 “操作序列”。
可以看出,当一个节点有了覆盖标记时,之后的加操作可以看作把这个覆盖标记的值增加 \(Z\)。
那么一个节点的 “操作序列” 就可以被刻画为 “加操作+覆盖操作”。
我们需要在线段树节点上再另外维护三个值 his,mxd,mxc
,分别表示这个节点的历史最大值、加标记的历史最大值、覆盖标记的历史最大值。
下放标记细节较多,需要注意各个标记的优先级。
int n,Q,a[N];struct Segtr{int val,his;int add,mxd,cov,mxc,tag;
}tr[N<<2];void Pushup(int p){tr[p].val=max(tr[p<<1].val,tr[p<<1|1].val);tr[p].his=max(tr[p<<1].his,tr[p<<1|1].his);
}void Buildtr(int p,int l,int r){tr[p].val=tr[p].his=-IINF;tr[p].mxd=tr[p].mxc=-IINF;if(l==r){tr[p].val=tr[p].his=a[l];return;}int mid=(l+r)>>1;Buildtr(p<<1,l,mid);Buildtr(p<<1|1,mid+1,r);Pushup(p);
}void WorkAdd(Segtr &p,Segtr &s){Ckmax(s.his,s.val+p.mxd);s.val+=p.add;if(s.tag){Ckmax(s.mxc,s.cov+p.mxd);s.cov+=p.add;}else{Ckmax(s.mxd,s.add+p.mxd);s.add+=p.add;}
}void WorkCov(Segtr &p,Segtr &s){if(!p.tag) return;Ckmax(s.his,p.mxc);s.val=p.cov;Ckmax(s.mxc,p.mxc);s.cov=p.cov;s.tag=1;
}void Spread(int p){WorkAdd(tr[p],tr[p<<1]);WorkAdd(tr[p],tr[p<<1|1]);WorkCov(tr[p],tr[p<<1]);WorkCov(tr[p],tr[p<<1|1]);tr[p].tag=tr[p].add=tr[p].cov=0;tr[p].mxc=tr[p].mxd=-IINF;
}void Update(int p,int l,int r,int L,int R,int d){if(L<=l&&r<=R){if(tr[p].tag){tr[p].cov+=d;Ckmax(tr[p].mxc,tr[p].cov);}else{tr[p].add+=d;Ckmax(tr[p].mxd,tr[p].add);}tr[p].val+=d;Ckmax(tr[p].his,tr[p].val);return;}Spread(p);int mid=(l+r)>>1;if(L<=mid) Update(p<<1,l,mid,L,R,d);if(R>mid) Update(p<<1|1,mid+1,r,L,R,d);Pushup(p);
}void Cover(int p,int l,int r,int L,int R,int d){if(L<=l&&r<=R){tr[p].cov=d;Ckmax(tr[p].mxc,d);tr[p].val=d;Ckmax(tr[p].his,d);tr[p].tag=1;return;}int mid=(l+r)>>1;Spread(p);if(L<=mid) Cover(p<<1,l,mid,L,R,d);if(R>mid) Cover(p<<1|1,mid+1,r,L,R,d);Pushup(p);
}int AskVal(int p,int l,int r,int L,int R){if(L<=l&&r<=R) return tr[p].val;int mid=(l+r)>>1,res=INT_MIN;Spread(p);if(L<=mid) Ckmax(res,AskVal(p<<1,l,mid,L,R));if(R>mid) Ckmax(res,AskVal(p<<1|1,mid+1,r,L,R));return res;
}int AskHis(int p,int l,int r,int L,int R){if(L<=l&&r<=R) return tr[p].his;int mid=(l+r)>>1,res=INT_MIN;Spread(p);if(L<=mid) Ckmax(res,AskHis(p<<1,l,mid,L,R));if(R>mid) Ckmax(res,AskHis(p<<1|1,mid+1,r,L,R));return res;
}signed main(){read(n);for(int i=1;i<=n;i++) read(a[i]);Buildtr(1,1,n);read(Q);while(Q--){char op[3];int l,r,v;scanf("%s",op);read(l),read(r);if(op[0]=='Q') printf("%lld\n",AskVal(1,1,n,l,r));if(op[0]=='A') printf("%lld\n",AskHis(1,1,n,l,r));if(op[0]=='P'){read(v);Update(1,1,n,l,r,v);}if(op[0]=='C'){read(v);Cover(1,1,n,l,r,v);}}return 0;
}