// Arbori de intervale.cpp : This file contains the 'main' function. Program execution begins and ends there.
//
#include <iostream>
#include <fstream>
#include <climits>
#define MAXN 100006
std::ifstream fin("arbint.in");
std::ofstream fout("arbint.out");
using namespace std;
int N, A[MAXN];
int T[4 * MAXN];
int M;
void build(int a[], int v, int tl, int tr)
{
if (tl == tr)
T[v] = a[tl];
else {
int tm = (tl + tr) / 2;
build(a, v * 2, tl, tm);
build(a, v * 2 + 1, tm + 1, tr);
T[v] = max(T[v * 2], T[v * 2 + 1]);
}
}
int maxi(int v, int tl, int tr, int l, int r)
{
if (l > r)
return INT_MIN;
if (l == tl && r == tr)
return T[v];
int tm = (tl + tr) / 2;
return max(maxi(v * 2, tl, tm, l, min(r, tm)),
maxi(v * 2 + 1, tm + 1, tr, max(l, tm + 1), r));
}
void update(int v, int tl, int tr, int pos, int new_val)
{
if (tl == tr)
T[v] = new_val;
else {
int tm = (tl + tr) / 2;
if (pos <= tm)
update(v * 2, tl, tm, pos, new_val);
else
update(v * 2 + 1, tm + 1, tr, pos, new_val);
T[v] = max(T[v * 2], T[v * 2 + 1]);
}
}
void Read()
{
fin >> N >> M;
for (int i = 1; i <= N; i++)
fin >> A[i];
}
void Solve()
{
for (int op, a, b; M--;)
{
fin >> op >> a >> b;
if (op == 0)
fout << maxi(1, 1, N, a, b) << "\n";
else
update(1, 1, N, a, b);
}
}
int main()
{
Read();
build(A, 1, 1, N);
Solve();
return 0;
}