#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=2e6+10;
int null=LONG_LONG_MAX;
struct node{
int lazy1,lazy2;
int val,l,r;
}tr[maxn*4];
int a[maxn];
void pushup(int rt){
tr[rt].val=max(tr[rt*2].val,tr[rt*2+1].val);
}
inline void coverdown(int rt)
{
if(tr[rt].lazy1!=null)
{
tr[rt*2].lazy2=tr[rt*2+1].lazy2=0;
tr[rt*2].val=tr[rt*2+1].val=tr[rt].lazy1;
tr[rt*2].lazy1=tr[rt*2+1].lazy1=tr[rt*2].lazy1;
tr[rt].lazy1=null;
}
}
inline void sumdown(int rt)
{
if(tr[rt].lazy2)
{
coverdown(rt);
tr[rt*2].val+=tr[rt].lazy2,tr[rt*2+1].val+=tr[rt].lazy2;
tr[rt*2].lazy2+=tr[rt].lazy2,tr[rt*2+1].lazy2+=tr[rt].lazy2;
tr[rt].lazy2=0;
}
}
inline void pushdown(int rt)
{
coverdown(rt);
sumdown(rt);
}
void build(int rt,int l,int r){
tr[rt].l=l,tr[rt].r=r;
if(l==r){
tr[rt].val=a[l];
tr[rt].lazy1=null;
tr[rt].lazy2=0;
return ;
}
int mid=(l+r)/2;
build(rt*2,l,mid);
build(rt*2+1,mid+1,r);
pushup(rt);
}
void modify(int rt,int x,int y,int k){
int l=tr[rt].l,r=tr[rt].r;
if(x<=l&&r<=y){
tr[rt].lazy2=0;
tr[rt].lazy1=tr[rt].val=k;
return ;
}
pushdown(rt);
int mid=(l+r)/2;
if(x<=mid) modify(rt*2,x,y,k);
if(y>mid) modify(rt*2+1,x,y,k);
pushup(rt);
}
void update(int rt,int x,int y,int k){
int l=tr[rt].l,r=tr[rt].r;
if(x<=l&&r<=y){
pushdown(rt);
tr[rt].lazy2+=k;
tr[rt].val+=k;
return ;
}
pushdown(rt);
int mid=(l+r)/2;
if(x<=mid) update(rt*2,x,y,k);
if(y>mid) update(rt*2+1,x,y,k);
pushup(rt);
}
int query(int rt,int x,int y){
int l=tr[rt].l,r=tr[rt].r;
if(r<x||l>y) return LONG_LONG_MIN;
if(x<=l&&r<=y){
return tr[rt].val;
}
pushdown(rt);
int mid=(l+r)/2,ans=LONG_LONG_MIN;
if(x<=mid) ans=max(ans,query(rt*2,x,y));
if(y>mid) ans=max(ans,query(rt*2+1,x,y));
return ans;
}
signed main(){
ios::sync_with_stdio(false);
int n,q;
cin >> n >> q;
for(int i=1;i<=n;i++){
cin >> a[i];
}
build(1,1,n);
for(int i=1;i<=n*4;i++) tr[i].lazy1=null;
while(q--){
int op,x,y;
cin >> op >> x >> y;
if(op==1){
int k;
cin >> k;
modify(1,x,y,k);
}if(op==2){
int k;
cin >> k;
update(1,x,y,k);
}if(op==3){
cout << query(1,x,y) << endl;
}
}
}