#include <fstream>
#define max(a, b) a > b ? a : b
using namespace std;
ifstream fin("arbint.in");
ofstream fout("arbint.out");
long long int tree[400005];
int n, m;
bool task;
void read();
long long int query(int node, int x, int y, int left, int right);
void update(int node, int pos, int val, int left, int right);
int main()
{
read();
return 0;
}
void read()
{
int i;
long long int a, b, x;
fin >> n >> m;
for (i = 1; i <= n; i++)
{
fin >> x;
update(1, i, x, 1, n);
}
for (i = 1; i <= m; i++)
{
fin >> task >> a >> b;
if (!task)
fout << query(1, 1, n, a, b) << '\n';
else
update(1, a, b, 1, n);
}
}
long long int query(int node, int left, int right, int x, int y)
{
// node = nodul radacina
// left = capatul stang al intervalului in care imi caut intervalul [a, b]
// right = capatul drept al intervalului in care imi caut intervalul [a, b]
// x = capatul [a -> nu se schimba niciodata
// y = capatul b] -> nu se schimba niciodata
int lo = 0, hi = 0;
if (x <= left && right <= y) // daca intervalul [a, b] este intreg inclus
return tree[node];
else // daca nu, il iau pe bucati
{
int mid = (left + (right - left) / 2);
if (x <= mid)
lo = query(2 * node, left, mid, x, y);
if (mid < y)
hi = query(2 * node + 1, mid + 1, right, x, y);
return max(lo, hi);
}
}
void update(int node, int pos, int val, int left, int right)
{
// node = nodul radacina
// pos = pozitia unde vreau sa pun valoarea val
// val = valoarea pe care vreau sa o pun pe pozitia val
// left = capatul stang al intervalului de cautare, initial 1
// right = capatul drept al intervalului de cautare, initial n
if (left == right)
tree[node] = val;
else
{
int mid = (left + (right - left) / 2);
if (pos <= mid) // caut in stanga
update(2 * node, pos, val, left, mid);
else // caut in dreapta
update(2 * node + 1, pos, val, mid + 1, right);
tree[node] = max(tree[2 * node], tree[2 * node + 1]);
// compar cele doua "submaxime" gasite
}
}