#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+10;
struct node{
int L,R;
int ma,lazy;
}t[maxn*4];
int n,m;
int a[maxn];
inline void up(int id){
t[id].ma=max(t[id*2].ma,t[id*2+1].ma);
return;
}
inline void down(int id){
t[id*2].lazy+=t[id].lazy;
t[id*2].ma+=t[id*2].lazy;
t[id*2+1].lazy+=t[id].lazy;
t[id*2+1].ma+=t[id*2+1].lazy;
t[id].lazy=0;
}
inline void build(int id,int l,int r){
t[id].L=l; t[id].R=r;
if(l==r){
t[id].ma=a[l]; return;
}
int mid=(l+r)/2;
build(id*2,l,mid); build(id*2+1,mid+1,r);
up(id);
}
inline void choose(int id,int l,int r,int val){
if(t[id].L > r || t[id].R < l) return;
if(t[id].L >= l && t[id].R <= r){
t[id].lazy=0; t[id].ma=val; return;
}
if(t[id].lazy != 0) down(id);
choose(id*2,l,r,val); choose(id*2+1,l,r,val);
up(id);
return;
}
inline void update(int id,int l,int r,int val){
if(t[id].L > r || t[id].R < l) return;
if(t[id].L >= l && t[id].R <= r){
t[id].lazy+=val; t[id].ma+=val;
return;
}
if(t[id].lazy != 0) down(id);
update(id*2,l,r,val); update(id*2+1,l,r,val);
up(id);
return;
}
int ask_max(int id,int l,int r){
if(t[id].L > r || t[id].R < l) return 0;
if(t[id].L >= l || t[id].R <= r) return t[id].ma;
if(t[id].lazy != 0) down(id);
return max(ask_max(id*2,l,r),ask_max(id*2+1,l,r));
}
int main(){
cin>>n>>m;
for(int i=1; i<=n; i++){
cin>>a[i];
}
build(1,1,n);
while(m--){
int opt,x,y,k;
cin>>opt;
if(opt==1){
cin>>x>>y>>k;
choose(1,x,y,k);
}else if(opt==2){
cin>>x>>y>>k;
update(1,x,y,k);
}else{
cin>>x>>y;
cout<<ask_max(1,x,y)<<endl;
}
}
return 0;
}