所谓吉司机线段树,就是吉司机种的线段树
(逃)
解析
之前也看过一些相关内容的博客,但是因标记乱七八糟,感觉过于高深而放弃了…
直到看到洛谷这篇博客,完全颠覆了我的认知。(怎么感觉语气像营销号)
原来是很小清新的算法,记录的标记虽然不少,但关键其实就在于记录懒标记历史最值这个操作上,而且思路很自然。
再次强推这篇博客!
在它的光辉下,一切更多的文字都是多余的。
我可不是在水文啊
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned ll
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define ok debug("OK\n")
inline ll read() {
ll x(0),f(1);char c=getchar();
while(!isdigit(c)) {if(c=='-') f=-1;c=getchar();}
while(isdigit(c)) {x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return x*f;
}
const int N=5e5+100;
const int inf=1e9;
int n,m;
#define mid ((l+r)>>1)
#define ls (k<<1)
#define rs (k<<1|1)
struct tree{
int siz,maxa,maxb,add1,add2,add3,add4,sec,cnt;
ll sum;
}tr[N<<2];
inline void pushup(int k){
tr[k].siz=tr[ls].siz+tr[rs].siz;
tr[k].sum=tr[ls].sum+tr[rs].sum;
tr[k].maxa=max(tr[ls].maxa,tr[rs].maxa);
tr[k].maxb=max(tr[ls].maxb,tr[rs].maxb);
tr[k].sec=max(tr[ls].sec,tr[rs].sec);
if(tr[ls].maxa<tr[k].maxa) tr[k].sec=max(tr[k].sec,tr[ls].maxa);
if(tr[rs].maxa<tr[k].maxa) tr[k].sec=max(tr[k].sec,tr[rs].maxa);
tr[k].cnt=0;
if(tr[k].maxa==tr[ls].maxa) tr[k].cnt+=tr[ls].cnt;
if(tr[k].maxa==tr[rs].maxa) tr[k].cnt+=tr[rs].cnt;
return;
}
inline void Add(int k,int add1,int add2,int add3,int add4){
tr[k].sum+=1ll*tr[k].cnt*add1+1ll*(tr[k].siz-tr[k].cnt)*add2;
tr[k].maxb=max(tr[k].maxb,tr[k].maxa+add3);
tr[k].maxa+=add1;
tr[k].add3=max(tr[k].add3,tr[k].add1+add3);
tr[k].add4=max(tr[k].add4,tr[k].add2+add4);
tr[k].add1+=add1;
tr[k].add2+=add2;
tr[k].sec+=add2;
return;
}
inline void pushdown(int k){
ll mx=max(tr[ls].maxa,tr[rs].maxa);
if(mx==tr[ls].maxa) Add(ls,tr[k].add1,tr[k].add2,tr[k].add3,tr[k].add4);
else Add(ls,tr[k].add2,tr[k].add2,tr[k].add4,tr[k].add4);
if(mx==tr[rs].maxa) Add(rs,tr[k].add1,tr[k].add2,tr[k].add3,tr[k].add4);
else Add(rs,tr[k].add2,tr[k].add2,tr[k].add4,tr[k].add4);
tr[k].add1=tr[k].add2=tr[k].add3=tr[k].add4=0;
}
int a[N];
void build(int k,int l,int r){
if(l==r){
tr[k].siz=1;
tr[k].maxa=tr[k].maxb=tr[k].sum=a[l];
tr[k].cnt=1;
tr[k].sec=-inf;
tr[k].add1=tr[k].add2=tr[k].add3=tr[k].add4=0;
return;
}
build(ls,l,mid);
build(rs,mid+1,r);
pushup(k);
return;
}
void upd_add(int k,int l,int r,int x,int y,int w){
if(x<=l&&r<=y){
Add(k,w,w,w,w);return;
}
pushdown(k);
if(x<=mid) upd_add(ls,l,mid,x,y,w);
if(y>mid) upd_add(rs,mid+1,r,x,y,w);
pushup(k);
}
void upd_min(int k,int l,int r,int x,int y,int w){
if(tr[k].maxa<=w) return;
if(x<=l&&r<=y&&tr[k].sec<w){
Add(k,w-tr[k].maxa,0,w-tr[k].maxa,0);
return;
}
pushdown(k);
if(x<=mid) upd_min(ls,l,mid,x,y,w);
if(y>mid) upd_min(rs,mid+1,r,x,y,w);
pushup(k);
}
ll ask_sum(int k,int l,int r,int x,int y){
if(x<=l&&r<=y) return tr[k].sum;
ll res(0);
pushdown(k);
if(x<=mid) res+=ask_sum(ls,l,mid,x,y);
if(y>mid) res+=ask_sum(rs,mid+1,r,x,y);
return res;
}
ll ask_maxa(int k,int l,int r,int x,int y){
if(x<=l&&r<=y) return tr[k].maxa;
ll res=-inf;
pushdown(k);
if(x<=mid) res=max(res,ask_maxa(ls,l,mid,x,y));
if(y>mid) res=max(res,ask_maxa(rs,mid+1,r,x,y));
return res;
}
ll ask_maxb(int k,int l,int r,int x,int y){
if(x<=l&&r<=y) return tr[k].maxb;
ll res=-inf;
pushdown(k);
if(x<=mid) res=max(res,ask_maxb(ls,l,mid,x,y));
if(y>mid) res=max(res,ask_maxb(rs,mid+1,r,x,y));
return res;
}
signed main(){
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
#endif
n=read();m=read();
for(int i=1;i<=n;i++) a[i]=read();
build(1,1,n);
for(int i=1;i<=m;i++){
int op=read(),l=read(),r=read(),w;
if(op<=2) w=read();
if(op==1) upd_add(1,1,n,l,r,w);
else if(op==2) upd_min(1,1,n,l,r,w);
else if(op==3) printf("%lld\n",ask_sum(1,1,n,l,r));
else if(op==4) printf("%lld\n",ask_maxa(1,1,n,l,r));
else printf("%lld\n",ask_maxb(1,1,n,l,r));
}
return 0;
}
/*
*/