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;
}

posted @ 2025-03-21 22:58  XP3301_Pipi  阅读(26)  评论(0)    收藏  举报
Title