#include <fstream>
using namespace std;
ifstream f("arbint.in");
ofstream g("arbint.out");
static constexpr int NMAX = (int)(1e5 + 1);
int n, A[NMAX];
class SegTree
{
int V[(NMAX << 1)];
private:
static inline int my_max(int a, int b)
{
return ((a > b) ? a : b);
}
public:
inline void Initialize(int node, int a, int b)
{
if (a == b)
{
V[node] = A[a];
return;
}
int mid = ((a + b) >> 1);
Initialize((node << 1), a, mid);
Initialize(((node << 1) + 1), (mid + 1), b);
V[node] = my_max(V[(node << 1)], V[((node << 1) + 1)]);
return;
}
inline void Update(int node, int a, int b, int pos, int val)
{
if (a == b)
{
V[node] = val;
return;
}
int mid = ((a + b) >> 1);
if (pos <= mid)
Update((node << 1), a, mid, pos, val);
if (pos > mid)
Update(((node << 1) + 1), (mid + 1), b, pos, val);
V[node] = my_max(V[(node << 1)], V[((node << 1) + 1)]);
return;
}
inline int Query(int node, int a, int b, int qa, int qb)
{
if (qa <= a && b <= qb)
return V[node];
int p_left = 0, p_right = 0;
int mid = ((a + b) >> 1);
if (qa <= mid)
p_left = Query((node << 1), a, mid, qa, qb);
if (qb > mid)
p_right = Query(((node << 1) + 1), (mid + 1), b, qa, qb);
return my_max(p_left, p_right);
}
} T;
int main()
{
f.tie(nullptr);
int Q = 0;
f >> n >> Q;
for (int i = 1; i <= n; ++i)
f >> A[i];
T.Initialize(1, 1, n);
for (int q = 1; q <= Q; ++q)
{
int type = 0, a = 0, b = 0;
f >> type >> a >> b;
if (type == 1)
T.Update(1, 1, n, a, b);
else
g << T.Query(1, 1, n, a, b) << '\n';
}
return 0;
}