# [学习笔记] [UR #11]元旦老人与数列 - segment tree beats学习笔记

mn表示区间最小值，se表示区间严格次小值（若没有就是INF）；
p表示区间加法标记，pn表示区间加法的最小前缀和标记（就是执行了若干次加法，求前缀和，最小的那个；显然不会比0大）。np表示最小值被加的数值标记，pnp表示最小值被加的最小前缀和标记，h表示最小值的历史最小值。

$mn+=c,se+=c,pn=min\left(pn,p+=c\right),\phantom{\rule{0ex}{0ex}}pnp=min\left(pnp,np+=c\right),h=min\left(h,mn\right)$$mn+=c,se+=c,pn=min(pn,p+=c),\\ pnp=min(pnp,np+=c),h=min(h,mn)$

$pn=min\left(pn,p+=d-mn\right),d=mn$$pn=min(pn,p+=d-mn),d=mn$

$se+={p}^{\prime },pn=min\left(pn,p+p{n}^{\prime }\right),\phantom{\rule{0ex}{0ex}}h=min\left(h,mn+pn{p}^{\prime }\right),\phantom{\rule{0ex}{0ex}}pnp=min\left(pnp,np+pn{p}^{\prime }\right),\phantom{\rule{0ex}{0ex}}mn+=n{p}^{\prime },np+=n{p}^{\prime },p+={p}^{\prime };$$se+=p',pn=min(pn,p+pn'),\\h=min(h,mn+pnp'),\\pnp=min(pnp,np+pnp'),\\mn+=np',np+=np',p+=p';$

#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;
}