题解:
原来的赋值操作相当于加上
−∞
−
∞
之后
chkmax
c
h
k
m
a
x
。
注意到给的数据保证0肯定作为最小值出现,相当于要维护加和
chkmax
c
h
k
m
a
x
和支持查询最小值个数的线段树,这明显是吉司机线段树。
同时维护 add,chkmax a d d , c h k m a x 只需要保证 add a d d 比 chkmax c h k m a x 先下传,如果在 chkmax c h k m a x 后 add a d d ,把 chkmax c h k m a x 的 tag t a g 加上 add a d d 的值即可。
#include <bits/stdc++.h>
typedef long long LL;
using namespace std;
const LL INF=(0x3f3f3f3f)*200ll;
inline int rd() {
char ch=getchar(); int i=0,f=1;
while(!isdigit(ch)) {if(ch=='-')f=-1; ch=getchar();}
while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=getchar();}
return i*f;
}
inline void W(LL x) {
static int buf[50];
if(!x) {putchar('0'); return;}
if(x<0) {putchar('-'); x=-x;}
while(x) {buf[++buf[0]]=x%10; x/=10;}
while(buf[0]) {putchar(buf[buf[0]--]+'0');}
}
const int N=3e5+50;
int n,m;
LL mn[N*4],se[N*4],mnc[N*4],atag[N*4],ctag[N*4];
inline void upt(int k) {
int lc=k<<1,rc=lc|1;
if(mn[lc]==mn[rc]) {
mn[k]=mn[lc];
mnc[k]=mnc[lc]+mnc[rc];
se[k]=min(se[lc],se[rc]);
} else {
if(mn[lc]>mn[rc]) swap(lc,rc);
mn[k]=mn[lc]; mnc[k]=mnc[lc];
se[k]=min(se[lc],mn[rc]);
}
}
inline void build(int k,int l,int r) {
atag[k]=0; ctag[k]=-INF;
if(l==r) {
mn[k]=rd(); se[k]=0x3f3f3f3f3f3f3f3f;
mnc[k]=1;
return;
} int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
upt(k);
}
inline void add(int k,int l,int r,LL v) {
if(ctag[k]!=-INF) ctag[k]+=v;
mn[k]+=v; se[k]+=v; atag[k]+=v;
}
inline void color(int k,int l,int r,LL v) {
if(mn[k]>=v) return;
if(ctag[k]>=v) return;
int mid=(l+r)>>1;
if((l!=r) && atag[k]) {
add(k<<1,l,mid,atag[k]);
add(k<<1|1,mid+1,r,atag[k]);
atag[k]=0;
}
if(se[k]>v) {
ctag[k]=v; mn[k]=v;
} else {
ctag[k]=-INF;
color(k<<1,l,mid,v);
color(k<<1|1,mid+1,r,v);
upt(k);
}
}
inline void pushdown(int k,int l,int r) {
int mid=(l+r)>>1;
if(atag[k]) {
add(k<<1,l,mid,atag[k]);
add(k<<1|1,mid+1,r,atag[k]);
atag[k]=0;
}
if(ctag[k]!=-INF) {
color(k<<1,l,mid,ctag[k]);
color(k<<1|1,mid+1,r,ctag[k]);
ctag[k]=-INF;
}
}
inline void modify1(int k,int l,int r,int L,int R,LL v) {
if(L<=l&&r<=R) {add(k,l,r,v); return;}
pushdown(k,l,r); int mid=(l+r)>>1;
if(R<=mid) modify1(k<<1,l,mid,L,R,v);
else if(L>mid) modify1(k<<1|1,mid+1,r,L,R,v);
else modify1(k<<1,l,mid,L,R,v),modify1(k<<1|1,mid+1,r,L,R,v);
upt(k);
}
inline void modify2(int k,int l,int r,int L,int R,LL v) {
if(L<=l&&r<=R) {color(k,l,r,v); return;}
pushdown(k,l,r); int mid=(l+r)>>1;
if(R<=mid) modify2(k<<1,l,mid,L,R,v);
else if(L>mid) modify2(k<<1|1,mid+1,r,L,R,v);
else modify2(k<<1,l,mid,L,R,v),modify2(k<<1|1,mid+1,r,L,R,v);
upt(k);
}
inline int query(int k,int l,int r,int L,int R) {
if(L<=l&&r<=R) {return (!mn[k])*mnc[k];}
pushdown(k,l,r); int mid=(l+r)>>1;
if(R<=mid) return query(k<<1,l,mid,L,R);
else if(L>mid) return query(k<<1|1,mid+1,r,L,R);
else return query(k<<1,l,mid,L,R)+query(k<<1|1,mid+1,r,L,R);
}
int main() {
n=rd(), m=rd();
build(1,1,n);
while(m--) {
int op=rd(),l=rd(),r=rd();
if(op==1) {
modify1(1,1,n,l,r,-INF);
modify2(1,1,n,l,r,rd());
} else if(op==2) {
modify1(1,1,n,l,r,rd());
modify2(1,1,n,l,r,0);
} else {W(query(1,1,n,l,r)); putchar('\n');}
}
}