#include<iostream>
#include<cstring>
using namespace std;
#define ll long long
//push_up,b_t,push_down,addtag,query,update;
const ll N = 1e6;
const ll INF = 1e10;
ll a[N],tree[N<<2],tag_add[N<<2],tag_mo[N<<2];
int n,q,op;
inline ll lson(ll p){ return p<<1; }
inline ll rson(ll p){ return p<<1|1; }
inline void push_up(ll p){ tree[p] = max(tree[lson(p)],tree[rson(p)]); }
inline void b_t(ll p,ll l,ll r){
if(l == r){ tree[p] = a[l]; tag_mo[p] = INF; return; }
tag_mo[p] = INF;
ll mid=(l+r)>>1;
b_t(lson(p),l,mid);
b_t(rson(p),mid+1,r);
push_up(p);
}
inline void addtag(ll p,ll x,int t){
if (t == 1){//改
tag_add[p] = 0;
tag_mo[p] = x;
tree[p] = x;
}
else{//加
if(tag_mo[p] == INF) tag_add[p]+=x;
else tag_mo[p]+=x;
tree[p]+=x;
}
}
inline void push_down(ll p,ll l,ll r){
if (tag_mo[p] == INF){
addtag(lson(p),tag_add[p],2);
addtag(rson(p),tag_add[p],2);
tag_add[p] = 0;
}
else {
addtag(lson(p),tag_mo[p],1);
addtag(rson(p),tag_mo[p],1);
tag_mo[p] = INF;
}
}
ll query(ll nl,ll nr,ll p,ll l,ll r){
if(nl<=l && nr>=r) return tree[p];
ll mid = (l+r)>>1;
ll ans = -INF;
push_down(p,l,r);
if(nl<=mid) ans = max(ans,query(nl,nr,lson(p),l,mid));
if(nr>mid) ans = max(ans,query(nl,nr,rson(p),mid+1,r));
return ans;
}
inline void update(ll nl,ll nr,ll p,ll l,ll r,ll x,int t){
if(nl<=l && nr>=r){
if (t == 1){
addtag(p,x,1);
return;
}
else {
addtag(p,x,2);
return;
}
}
push_down(p,l,r);
ll mid=(l+r)>>1;
if(t == 1){
if(nl<=mid) update(nl,nr,lson(p),l,mid,x,1);
if(nr>mid) update(nl,nr,rson(p),mid+1,r,x,1);
}
else {
if(nl<=mid) update(nl,nr,lson(p),l,mid,x,2);
if(nr>mid) update(nl,nr,rson(p),mid+1,r,x,2);
}
push_up(p);
}
int main(){
cin>>n>>q;
for (int i=1;i<=n;i++) cin>>a[i];
while(q--){
cin>>op;
if(op == 1){
ll nl,nr,d;
cin>>nl>>nr>>d;
update(nl,nr,1,1,n,d,1);
}
if(op == 2){
ll nl,nr,d;
cin>>nl>>nr>>d;
update(nl,nr,1,1,n,d,2);
}
if(op == 3){
ll nl,nr;
cin>>nl>>nr;
cout<<query(nl,nr,1,1,n)<<"\n";
}
// cout<<tree[2]<<" "<<tree[3]<<endl;
}
return 0;
}