首先对于区间对d取max操作可以认为是,如果d小于等于最小值那么没有影响;如果d大于等于严格次大值那么去递归左右儿子,然后push_up出这个节点的信息;因此真正意义上修改这个区间的情况是d介于最小值和严格次小值之间,这时候相当于只把区间中的最小值加上一些数字。也就是说,最小值的维护要和其余数字的维护分开来。
线段树维护:
mn表示区间最小值,se表示区间严格次小值(若没有就是INF);
p表示区间加法标记,pn表示区间加法的最小前缀和标记(就是执行了若干次加法,求前缀和,最小的那个;显然不会比0大)。np表示最小值被加的数值标记,pnp表示最小值被加的最小前缀和标记,h表示最小值的历史最小值。
那么每次加法(+c):
mn+=c,se+=c,pn=min(pn,p+=c),pnp=min(pnp,np+=c),h=min(h,mn)
m
n
+
=
c
,
s
e
+
=
c
,
p
n
=
m
i
n
(
p
n
,
p
+
=
c
)
,
p
n
p
=
m
i
n
(
p
n
p
,
n
p
+
=
c
)
,
h
=
m
i
n
(
h
,
m
n
)
而每次取max(对d,并且mn< d< se)
pn=min(pn,p+=d−mn),d=mn
p
n
=
m
i
n
(
p
n
,
p
+
=
d
−
m
n
)
,
d
=
m
n
每次push_down的时候,要注意是其左子树的最小值小还是右子树的最小值小来决定np和pnp的下传情况(别忘了np和pnp只对应修改最小值,所以你只能下传给最小值更小的子树,否则就要下传p和pn)。假设下传的是p’,pn’,np’,pnp’:
se+=p′,pn=min(pn,p+pn′),h=min(h,mn+pnp′),pnp=min(pnp,np+pnp′),mn+=np′,np+=np′,p+=p′;
s
e
+
=
p
′
,
p
n
=
m
i
n
(
p
n
,
p
+
p
n
′
)
,
h
=
m
i
n
(
h
,
m
n
+
p
n
p
′
)
,
p
n
p
=
m
i
n
(
p
n
p
,
n
p
+
p
n
p
′
)
,
m
n
+
=
n
p
′
,
n
p
+
=
n
p
′
,
p
+
=
p
′
;
然后没了。细节上要注意se有可能是INF要特判否则可能会有点问题。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<climits>
#include<assert.h>
#define gc getchar()
#define N 500010
#define INF (INT_MAX/2)
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
int a[N];
inline int inn()
{
int x=0,s=1,ch;while(((ch=gc)<'0'||ch>'9')&&ch!='-');
if(ch^'-') x=ch^'0';else s=-1;
while((ch=gc)>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^'0');
return s*x;
}
struct segment{
int l,r,mn,se,np,pnp,p,pn,h;
segment *ch[2];
}*rt;
inline int push_up(segment* &rt)
{
int v0=0,v1=0,p;
rt->mn=min(v0=rt->ch[0]->mn,v1=rt->ch[1]->mn);
if(v0==v1) rt->se=min(rt->ch[0]->se,rt->ch[1]->se);
else p=v0>v1,rt->se=min(rt->ch[p]->se,rt->ch[p^1]->mn);
return rt->h=min(rt->ch[0]->h,rt->ch[1]->h),0;
}
inline int update_tags(segment* &rt,int p,int pn,int np,int pnp)
{
if(rt->se<INF) rt->se+=p;rt->pn=min(rt->pn,rt->p+pn);
return rt->h=min(rt->h,rt->mn+pnp),
rt->pnp=min(rt->pnp,rt->np+pnp),
rt->mn+=np,rt->np+=np,rt->p+=p;
}
inline int update_max(segment* &rt,int v)
{
if(v<=rt->mn) return 0;
rt->pnp=min(rt->pnp,rt->np+=v-rt->mn);
return rt->h=min(rt->h,rt->mn=v),0;
}
inline int push_down(segment* &rt)
{
int v0=rt->ch[0]->mn,v1=rt->ch[1]->mn,p=rt->p,np=rt->np,pnp=rt->pnp,pn=rt->pn;
if(v0==v1) update_tags(rt->ch[0],p,pn,np,pnp),update_tags(rt->ch[1],p,pn,np,pnp);
if(v0<v1) update_tags(rt->ch[0],p,pn,np,pnp),update_tags(rt->ch[1],p,pn,p,pn);
if(v0>v1) update_tags(rt->ch[0],p,pn,p,pn),update_tags(rt->ch[1],p,pn,np,pnp);
rt->p=0,rt->pn=0,rt->np=0,rt->pnp=0;return 0;
}
int build(segment* &rt,int l,int r)
{
rt=new segment,rt->l=l,rt->r=r,rt->p=rt->np=rt->pnp=0;int mid;
if(l==r) return rt->h=rt->mn=a[l],rt->se=INF;mid=(l+r)>>1;
build(rt->ch[0],l,mid),build(rt->ch[1],mid+1,r);
return push_up(rt);
}
int update_plus(segment* &rt,int s,int t,int v)
{
int l=rt->l,r=rt->r,mid=(l+r)>>1;
if(s<=l&&r<=t) return update_tags(rt,v,min(v,0),v,min(v,0));
if(rt->p||rt->np||rt->pnp) push_down(rt);
// assert(rt->mn==min(rt->ch[0]->mn,rt->ch[1]->mn));
// if(rt->mn>rt->ch[0]->mn) update_max(rt->ch[0],rt->mn);
// if(rt->mn>rt->ch[1]->mn) update_max(rt->ch[1],rt->mn);
if(s<=mid) update_plus(rt->ch[0],s,t,v);
if(mid<t) update_plus(rt->ch[1],s,t,v);
return push_up(rt);
}
int update_max(segment* &rt,int s,int t,int v)
{
if(v<=rt->mn) return 0;int l=rt->l,r=rt->r,mid=(l+r)>>1;
if(s<=l&&r<=t&&v<rt->se) return update_max(rt,v);
if(rt->p||rt->np||rt->pnp) push_down(rt);
// assert(rt->mn==min(rt->ch[0]->mn,rt->ch[1]->mn));
// if(rt->mn>rt->ch[0]->mn) update_max(rt->ch[0],rt->mn);
// if(rt->mn>rt->ch[1]->mn) update_max(rt->ch[1],rt->mn);
if(s<=mid) update_max(rt->ch[0],s,t,v);
if(mid<t) update_max(rt->ch[1],s,t,v);
return push_up(rt);
}
int query(segment* &rt,int s,int t,int k)
{
int l=rt->l,r=rt->r,mid=(l+r)>>1,ans=INF;
if(s<=l&&r<=t) return k?rt->mn:rt->h;
if(rt->p||rt->np||rt->pnp) push_down(rt);
// assert(rt->mn==min(rt->ch[0]->mn,rt->ch[1]->mn));
// if(rt->mn>rt->ch[0]->mn) update_max(rt->ch[0],rt->mn);
// if(rt->mn>rt->ch[1]->mn) update_max(rt->ch[1],rt->mn);
if(s<=mid) ans=min(ans,query(rt->ch[0],s,t,k));
if(mid<t) ans=min(ans,query(rt->ch[1],s,t,k));
return ans;
}
inline int show(segment* &rt)
{
int l=rt->l,r=rt->r,mn=rt->mn,se=rt->se,p=rt->p,np=rt->np,pnp=rt->pnp,h=rt->h,pn=rt->pn;
debug(l)sp,debug(r)sp,debug(mn)sp,debug(se)sp,debug(p)sp,debug(pn)sp,debug(np)sp,debug(pnp)sp,debug(h)ln;
if(l==r) return 0;show(rt->ch[0]),show(rt->ch[1]);return 0;
}
int main()
{
// freopen("a.in","r",stdin),freopen("std.out","w",stdout);
int n=inn(),m=inn(),s,t,v;
for(int i=1;i<=n;i++) a[i]=inn();
build(rt,1,n);
while(m--)
{
switch(inn())
{
case 1:s=inn(),t=inn(),v=inn(),update_plus(rt,s,t,v);break;
case 2:s=inn(),t=inn(),v=inn(),update_max(rt,s,t,v);break;
case 3:s=inn(),t=inn(),printf("%d\n",query(rt,s,t,1));break;
case 4:s=inn(),t=inn(),printf("%d\n",query(rt,s,t,0));break;
}
// show(rt);cerr ln;
}
return 0;
}