BZOJ4355: Play with sequence

BZOJ4355: Play with sequence

https://lydsy.com/JudgeOnline/problem.php?id=4355

分析:

  • 模板题。
  • \(2\)操作看成先区间加再区间取\(max\)
  • 查询转化成求最小值个数。
  • 需要维护\(3\)个标记。
  • 这里我比较naive地维护了三个标记,多维护了一个最小值需要加的值。
  • 然后下传的时候对左右儿子判断是否应该下传。
  • 实际上不需要,直接修改最小值即可。

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cmath>
using namespace std;
#define N 1200050
#define ls p<<1
#define rs p<<1|1
typedef long long ll;
const ll inf = 1ll<<60;
int n,m;
ll a[N],mn[N],ci[N],tag1[N],tag2[N],tag3[N];
int cnt[N],len[N];
void giv1(int p,ll v) {
    tag1[p]=v; 
    tag2[p]=0;
    tag3[p]=0;
    mn[p]=v; 
    ci[p]=inf;
    cnt[p]=len[p];
}
void giv2(int p,ll v) {
    tag2[p]+=v;
    mn[p]+=v;
    ci[p]+=v;
}
void giv3(int p,ll v) {
    tag3[p]+=v; 
    mn[p]+=v;
}
void pushdown(int p) {
    if(tag1[p]!=-1) giv1(ls,tag1[p]),giv1(rs,tag1[p]),tag1[p]=-1;
    if(tag2[p]) giv2(ls,tag2[p]),giv2(rs,tag2[p]),tag2[p]=0;
    if(tag3[p]) {
        if(mn[ls]+tag3[p]==mn[p]) giv3(ls,tag3[p]);
        if(mn[rs]+tag3[p]==mn[p]) giv3(rs,tag3[p]);
        tag3[p]=0;
    }
}
void pushup(int p) {
    mn[p]=min(mn[ls],mn[rs]);
    if(mn[ls]==mn[rs]) ci[p]=min(ci[ls],ci[rs]),cnt[p]=cnt[ls]+cnt[rs];
    else {
        if(mn[ls]<mn[rs]) ci[p]=min(ci[ls],mn[rs]),cnt[p]=cnt[ls];
        else ci[p]=min(ci[rs],mn[ls]),cnt[p]=cnt[rs];
    }
}
void build(int l,int r,int p) {
    tag1[p]=-1;
    len[p]=r-l+1;
    if(l==r) {
        mn[p]=a[l];
        ci[p]=inf;
        cnt[p]=1;
        return ;
    }
    int mid=(l+r)>>1;
    build(l,mid,ls); build(mid+1,r,rs);
    pushup(p);
}
void updadd(int l,int r,int x,int y,int v,int p) {
    if(x<=l&&y>=r) {
        giv2(p,v); return ;     
    }
    int mid=(l+r)>>1;
    pushdown(p);
    if(x<=mid) updadd(l,mid,x,y,v,ls);
    if(y>mid) updadd(mid+1,r,x,y,v,rs);
    pushup(p);
}
void updcov(int l,int r,int x,int y,int v,int p) {
    if(x<=l&&y>=r) {
        giv1(p,v); return ;
    }
    int mid=(l+r)>>1;
    pushdown(p);
    if(x<=mid) updcov(l,mid,x,y,v,ls);
    if(y>mid) updcov(mid+1,r,x,y,v,rs);
    pushup(p);
}
void updmax(int l,int r,int x,int y,int p) {
    if(mn[p]>=0) return ;
    if(x<=l&&y>=r&&ci[p]>0) {
        giv3(p,-mn[p]); return ;
    }
    if(l==r) {giv1(p,0); return ;}
    int mid=(l+r)>>1;
    pushdown(p);
    if(x<=mid) updmax(l,mid,x,y,ls);
    if(y>mid) updmax(mid+1,r,x,y,rs);
    pushup(p);
}
int query(int l,int r,int x,int y,int p) {
    if(x<=l&&y>=r) return (mn[p]==0)*cnt[p];
    int mid=(l+r)>>1,re=0;
    pushdown(p);
    if(x<=mid) re+=query(l,mid,x,y,ls);
    if(y>mid) re+=query(mid+1,r,x,y,rs);
    return re;
}
int main() {
    scanf("%d%d",&n,&m);
    int i,opt,x,y,z;
    for(i=1;i<=n;i++) scanf("%lld",&a[i]);
    build(1,n,1);
    while(m--) {
        scanf("%d%d%d",&opt,&x,&y);
        if(opt==1) {
            scanf("%d",&z);
            updcov(1,n,x,y,z,1);
        }else if(opt==2) {
            scanf("%d",&z);
            updadd(1,n,x,y,z,1);
            updmax(1,n,x,y,1);
        }else {
            printf("%d\n",query(1,n,x,y,1));
        }
    }
}

转载于:https://www.cnblogs.com/suika/p/10204775.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值