#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e6 + 5, INF = 1e18;
struct Tree {
int val, lazy_add, lazy_change;
} tree[N<<3];
int a[N];
void push_up (int rt) {
tree[rt].val = max(tree[rt<<1].val, tree[rt<<1|1].val);
}
void push_down_change (int rt, int l, int r) {
if (tree[rt].lazy_change != -INF) {
int lazy = tree[rt].lazy_change, ls = rt << 1, rs = ls | 1;
tree[ls].lazy_add = tree[rs].lazy_add = 0;
tree[ls].lazy_change = lazy;
tree[rs].lazy_change = lazy;
tree[ls].val = lazy;
tree[rs].val = lazy;
tree[rt].lazy_change = -INF;
}
}
void push_down_add (int rt, int l, int r) {
if (tree[rt].lazy_add) {
push_down_change(rt, l, r);
int lazy = tree[rt].lazy_add, ls = rt << 1, rs = ls | 1;
tree[ls].lazy_add += lazy;
tree[rs].lazy_add += lazy;
tree[ls].val += lazy;
tree[rs].val += lazy;
tree[rt].lazy_add = 0;
}
}
void push_down (int rt, int l, int r) {
push_down_change(rt, l, r);
push_down_add(rt, l, r);
}
void build (int rt, int l, int r) {
if (l == r) {
tree[rt].val = a[l];
tree[rt].lazy_add = 0;
tree[rt].lazy_change = -INF;
return;
}
int mid = (l + r) >> 1;
build(rt << 1, l, mid);
build(rt << 1 | 1, mid + 1, r);
push_up(rt);
}
void update (int rt, int l, int r, int ql, int qr, int num, int op) {
if (l > qr || r < ql) return;
if (l >= ql && r <= qr) {
if (op == 1) {
tree[rt].lazy_add = 0;
tree[rt].val = num;
tree[rt].lazy_change = num;
} else if (op == 2) {
push_down_change(rt, l, r);
tree[rt].val += num;
tree[rt].lazy_add += num;
}
return;
}
push_down(rt, l, r);
int mid = (l + r) >> 1;
update(rt << 1, l, mid, ql, qr, num, op);
update(rt << 1 | 1, mid + 1, r, ql, qr, num, op);
push_up(rt);
}
int query (int rt, int l, int r, int ql, int qr) {
if (r < ql || qr < l) return -INF;
if (ql <= l && r <= qr) return tree[rt].val;
push_down(rt, l, r);
int mid = (l + r) >> 1;
return max(query(rt << 1, l, mid, ql, qr), query(rt << 1 | 1, mid + 1, r, ql, qr));
}
signed main () {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int n, q, op, x, y, z;
cin >> n >> q;
for (int i = 1; i <= n; i++) cin >> a[i];
build(1, 1, n);
while (q--) {
cin >> op >> x >> y;
if (op == 1 || op == 2) cin >> z, update(1, 1, n, x, y, z, op);
else cout << query(1, 1, n, x, y) << endl;
}
return 0;
}