#include <iostream>
#include <cstdio>
#include <vector>
#include <cassert>
using namespace std;
static constexpr int INF = ((int)(1e9) + 1);
namespace InParser
{
static constexpr int BSIZE = (1 << 16);
char buff[BSIZE];
int pos = (BSIZE - 1);
char get_char()
{
++pos;
if (pos == BSIZE)
{
int n = fread(buff, 1, BSIZE, stdin);
if (n != BSIZE)
for (int i = n; i < BSIZE; ++i)
buff[i] = 0;
pos = 0;
}
return buff[pos];
}
int get_int()
{
int sign = (+1), answer = 0;
for (;;)
{
char x = get_char();
if (x == '-')
{
sign = (-1);
break;
}
if ((x >= '0') && (x <= '9'))
{
answer = ((int)(x - '0'));
break;
}
}
for (;;)
{
char ch = get_char();
if ((ch >= '0') && (ch <= '9'))
answer = (answer * 10) + ((int)(ch - '0'));
else
break;
}
return (sign * answer);
}
};
class Node
{
int val;
inline int my_max(const int x, const int y) const { return ((x > y) ? x : y); }
public:
Node() : val(-INF) {}
Node(const int x) : val(x) {}
Node operator+(const Node &other)
{
return Node(my_max((*this).val, other.val));
}
void set_val(const int x) { val = x; }
int get_val() const { return val; }
};
class SegmentTree
{
int n;
vector<Node> tree;
void build(const int node, const int left, const int right, const vector<int> &input = {}, const int pos = 0, const int val = 0)
{
if (left > right)
return;
if (left == right)
{
if (!input.empty())
tree[node].set_val(input[(left - 1)]);
else
tree[node].set_val(val);
return;
}
int mid = ((left + right) >> 1);
if (!input.empty())
{
build((node << 1), left, mid, input, pos, val),
build(((node << 1) + 1), (mid + 1), right, input, pos, val);
}
else
{
if (pos <= mid)
build((node << 1), left, mid, input, pos, val);
else
build(((node << 1) + 1), (mid + 1), right, input, pos, val);
}
tree[node] = tree[(node << 1)] + tree[((node << 1) + 1)];
return;
}
Node ask(const int node, const int left, const int right, const int ql, const int qr)
{
if (left > right)
return Node();
if (ql <= left && right <= qr)
return tree[node];
int mid = ((left + right) >> 1);
Node p_left, p_right;
if (ql <= mid)
p_left = ask((node << 1), left, mid, ql, qr);
if (qr > mid)
p_right = ask(((node << 1) + 1), (mid + 1), right, ql, qr);
return (p_left + p_right);
}
public:
SegmentTree(const int size, const vector<int> &input)
{
n = size;
tree.resize((n << 2) + 1);
assert(n == (int)input.size());
build(1, 1, n, input);
return;
}
void update(const int pos, const int val)
{
build(1, 1, n, {}, pos, val);
return;
}
int query(const int l, const int r)
{
return ask(1, 1, n, l, r).get_val();
}
void print()
{
for (int i = 1; i < (n << 1); ++i)
cout << tree[i].get_val() << ' ';
cout << '\n';
return;
}
};
int main()
{
ios_base ::sync_with_stdio(false);
cin.tie(nullptr);
freopen("arbint.in", "r", stdin);
freopen("arbint.out", "w", stdout);
int n(InParser ::get_int()), m(InParser ::get_int());
vector<int> v(n, 0);
for (int i = 0; i < n; ++i)
v[i] = InParser ::get_int();
SegmentTree S(n, v);
for (int t = 0; t < m; ++t)
{
short int type = ((short)InParser ::get_int());
int a = InParser ::get_int(), b = InParser ::get_int();
if (type == 0)
printf("%d\n", S.query(a, b));
else
S.update(a, b);
}
return 0;
}