#include "bits/stdc++.h"
using namespace std;
#define int long long
#define root tr[u]
#define left tr[u << 1]
#define right tr[u << 1 ^ 1]
const int N = 1e6 + 5;
int c[N];
int n, q;
struct Node
{
int l, r;
int max;
int add = 0, mul = 1;
}tr[N * 4];
void pushup(int u)
{
root.max = max(left.max, right.max);
}
void pushdown(int u)
{
if (root.mul != 1)
{
left.mul *= root.mul;
left.max *= root.mul;
right.mul *= root.mul;
right.max *= root.mul;
root.mul = 1;
}
if (root.add)
{
left.add += root.add;
left.max += root.add;
right.add += root.add;
right.max += root.add;
root.add = 0;
}
}
void build(int u, int l, int r)
{
if (l == r)
{
root = {l, r, c[l]};
return;
}
root = {l, r};
int mid = l + r >> 1;
build(u << 1, l, mid), build(u << 1 ^ 1, mid + 1, r);
pushup(u);
}
void modify(int u, int l, int r, int mul, int add)
{
if (root.l >= l && root.r <= r)
{
root.max = root.max * mul + add;
root.add += add;
root.mul *= mul;
// pushdown(u);
}
else
{
int mid = root.l + root.r >> 1;
pushdown(u);
if (l <= mid) modify(u << 1, l, r, mul, add);
if (r > mid) modify(u << 1 ^ 1, l, r, mul, add);
pushup(u);
}
}
int query(int u, int l, int r)
{
if (root.l >= l && root.r <= r)
return root.max;
int mid = root.l + root.r >> 1;
int res = -0x3f3f3f3f;
pushdown(u);
if (l <= mid) res = query(u << 1, l, r);
if (r > mid) res = max(query(u << 1 ^ 1, l, r), res);
return res;
}
void test()
{
// cout << "\t";
// for (int i = 1; i <= n; ++i)
// cout << query(1, i, i) << " ";
// cout << endl;
}
signed main()
{
scanf("%lld%lld", &n, &q);
for (int i = 1; i <= n; ++i) scanf("%lld", &c[i]);
build(1, 1, n);
test();
while (q --)
{
int a, l, r;
scanf("%lld%lld%lld", &a, &l ,&r);
if (r < l) swap(l, r);
if (a == 1)
{
int x;
scanf("%lld", &x);
modify(1, l, r, 0, x);
}
else if (a == 2)
{
int x;
scanf("%lld", &x);
modify(1, l, r, 1, x);
}
else
printf("%lld\n", query(1, l, r));
test();
}
return 0;
}