P4314 CPU 监控(区间历史最值)
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;
}

浙公网安备 33010602011771号