BZOJ4355:Play with sequence——题解

2023-01-07,,

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+;
inline int read(){
int X=,w=;char ch=;
while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
while(isdigit(ch))X=(X<<)+(X<<)+(ch^),ch=getchar();
return w?-X:X;
}
int n,m,b[N],cnt[N*];
ll mn[N*],se[N*],lzmn[N*],lzad[N*];
inline void upt(int a){
int ls=a<<,rs=a<<|;
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<<,rs=a<<|;
if(lzad[a]){
pushadd(ls,lzad[a]);
pushadd(rs,lzad[a]);
lzad[a]=;
}
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]=;
if(l==r){
mn[a]=b[l];se[a]=INF;cnt[a]=;
return;
}
int mid=(l+r)>>;
build(a<<,l,mid);build(a<<|,mid+,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]==&&x<=))return;
if(l1<=l&&r<=r1){
if(mn[a]+x>=){
pushadd(a,x);
return;
}
else if(se[a]==INF||se[a]+x>){
pushadd(a,x);
mn[a]=;lzmn[a]=;
return;
}
}
int mid=(l+r)>>;
push(a);
add(a<<,l,mid,l1,r1,x);add(a<<|,mid+,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)>>;
push(a);
cover(a<<,l,mid,l1,r1,x);cover(a<<|,mid+,r,l1,r1,x);
upt(a);
}
int qry(int a,int l,int r,int l1,int r1){
if(r<l1||r1<l)return ;
if(l1<=l&&r<=r1){
if(!mn[a])return cnt[a];
return ;
}
int mid=(l+r)>>;
push(a);
return qry(a<<,l,mid,l1,r1)+qry(a<<|,mid+,r,l1,r1);
}
int main(){
n=read(),m=read();
for(int i=;i<=n;i++)b[i]=read();
build(,,n);
while(m--){
int op=read(),x=read(),y=read();
if(op==)cover(,,n,x,y,read());
if(op==)add(,,n,x,y,read());
if(op==)printf("%d\n",qry(,,n,x,y));
}
return ;
}

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

+本文作者:luyouqi233。               +

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

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

BZOJ4355:Play with sequence——题解的相关教程结束。

《BZOJ4355:Play with sequence——题解.doc》

下载本文的Word格式文档,以方便收藏与打印。