BZOJ4355:Play with sequence——题解

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

维护一个长度为N的序列a,现在有三种操作:
1)给出参数U,V,C,将a[U],a[U+1],...,a[V-1],a[V]都赋值为C。
2)给出参数U,V,C,对于区间[U,V]里的每个数i,将a[i]赋值为max(a[i]+C,0)。
3)给出参数U,V,输出a[U],a[U+1],...,a[V-1],a[V]里值为0的数字个数。

吉如一论文板子题(当然所有的操作都来自论文拼起来的那当然是板子了。)

(本题解适合知道基本的吉司机线段树操作的人看。)

1操作根据玄学势能分析如果当前区间数都相等的话就可以转换成加操作,如果不相等会变成相等。

所以我们只要暴力做1操作(连lazy标记都不用打)即可。

2操作拆成两个操作,一次是区间+c,一次是区间a[i]=max(a[i],0)。

3操作实际就是问当前区间最小值为0时最小值个数。

#include<map>
#include<cmath>
#include<stack>
#include<queue>
#include<cstdio>
#include<cctype>
#include<vector>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const ll INF=5e18;
const int N=3e5+5;
inline int read(){
    int X=0,w=0;char ch=0;
    while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
    while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    return w?-X:X;
}
int n,m,b[N],cnt[N*4];
ll mn[N*4],se[N*4],lzmn[N*4],lzad[N*4];
inline void upt(int a){
    int ls=a<<1,rs=a<<1|1;
    if(mn[ls]==mn[rs]){
    mn[a]=mn[ls];se[a]=min(se[ls],se[rs]);
    cnt[a]=cnt[ls]+cnt[rs];
    }
    else if(mn[ls]<mn[rs]){
    mn[a]=mn[ls];se[a]=min(se[ls],mn[rs]);
    cnt[a]=cnt[ls];
    }else{
    mn[a]=mn[rs];se[a]=min(se[rs],mn[ls]);
    cnt[a]=cnt[rs];
    }
}
inline void pushadd(int a,ll x){
    mn[a]+=x;lzad[a]+=x;
    if(lzmn[a]!=-INF)lzmn[a]+=x;
    if(se[a]!=INF)se[a]+=x;
}
inline void push(int a){
    int ls=a<<1,rs=a<<1|1;
    if(lzad[a]){
    pushadd(ls,lzad[a]);
    pushadd(rs,lzad[a]);
    lzad[a]=0;
    }
    if(lzmn[a]!=-INF){
    if(mn[ls]<lzmn[a]){
           mn[ls]=lzmn[a];lzmn[ls]=lzmn[a];
    }
    if(mn[rs]<lzmn[a]){
               mn[rs]=lzmn[a];lzmn[rs]=lzmn[a];
    }
    lzmn[a]=-INF;
    }
}
void build(int a,int l,int r){
    lzmn[a]=-INF;lzad[a]=0;
    if(l==r){
    mn[a]=b[l];se[a]=INF;cnt[a]=1;
    return;
    }
    int mid=(l+r)>>1;
    build(a<<1,l,mid);build(a<<1|1,mid+1,r);
    upt(a);
}
void add(int a,int l,int r,int l1,int r1,int x){
    if(r<l1||r1<l||(se[a]==INF&&mn[a]==0&&x<=0))return;
    if(l1<=l&&r<=r1){
    if(mn[a]+x>=0){
        pushadd(a,x);
        return;
    }
    else if(se[a]==INF||se[a]+x>0){
        pushadd(a,x);
        mn[a]=0;lzmn[a]=0;
        return;
    }
    }
    int mid=(l+r)>>1;
    push(a);
    add(a<<1,l,mid,l1,r1,x);add(a<<1|1,mid+1,r,l1,r1,x);
    upt(a);
}
void cover(int a,int l,int r,int l1,int r1,int x){
    if(r<l1||r1<l)return;
    if(l1<=l&&r<=r1&&se[a]==INF){
    pushadd(a,(ll)x-mn[a]);
    return;
    }
    int mid=(l+r)>>1;
    push(a);
    cover(a<<1,l,mid,l1,r1,x);cover(a<<1|1,mid+1,r,l1,r1,x);
    upt(a);
}
int qry(int a,int l,int r,int l1,int r1){
    if(r<l1||r1<l)return 0;
    if(l1<=l&&r<=r1){
    if(!mn[a])return cnt[a];
    return 0;
    }
    int mid=(l+r)>>1;
    push(a);
    return qry(a<<1,l,mid,l1,r1)+qry(a<<1|1,mid+1,r,l1,r1);
}
int main(){
    n=read(),m=read();
    for(int i=1;i<=n;i++)b[i]=read();
    build(1,1,n);
    while(m--){
    int op=read(),x=read(),y=read();
    if(op==1)cover(1,1,n,x,y,read());
    if(op==2)add(1,1,n,x,y,read());
    if(op==3)printf("%d\n",qry(1,1,n,x,y));
    }
    return 0;
}

+++++++++++++++++++++++++++++++++++++++++++

 +本文作者:luyouqi233。               +

 +欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+

+++++++++++++++++++++++++++++++++++++++++++

转载于:https://www.cnblogs.com/luyouqi233/p/9155814.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值