#include <iostream>
#include <fstream>
using namespace std;
ifstream f("arbint.in");
ofstream g("arbint.out");
int v[400020];/// nodurile arborelului in care tinem maximul din interval
int a[100000];
int n, m;
int MAX;
int ft_max(int a, int b)
{
return a >= b ? a : b;
}
void build_arbint(int node, int left, int right)
{
/// [left, right], capetele intervalului tinute in nod
int middle;
if (left == right)
{
/// am ajuns intr-un capat
v[node] = a[left];
return ;
}
middle = (left + right) / 2;
build_arbint(2 * node, left, middle); /// fiul stang
build_arbint(2 * node + 1, middle + 1, right); /// fiul drept
v[node] = ft_max(v[2 * node], v[2 * node + 1]);
}
void update(int node, int left, int right, int poz, int new_val)
{
int middle;
if (left == right)
{
v[node] = new_val;
return ;
}
middle = (left + right) / 2;
if (poz <= middle) /// poz = fiul stang
update(2 * node, left, middle, poz, new_val);
else /// poz = fiul drept
update(2 * node + 1, middle + 1, right, poz, new_val);
v[node] = ft_max(v[2 * node], v[2 * node + 1]);
}
void query(int node, int left, int right, int x, int y) /// max pe [x, y]
{
int middle;
if (right <= y && left >= x)
{
MAX = ft_max(MAX, v[node]);
return ;
}
middle = (left + right) / 2;
if (x <= middle)
query(2 * node, left, middle, x, y); /// mergem in fiul stang
if (y > middle)
query(2 * node + 1, middle + 1, right, x, y); /// mergem in fiul drept
}
void rezolvare(void)
{
int op, x, y;
f >> n >> m;
for (int i = 1; i <= n; i++)
f >> a[i];
build_arbint(1, 1, n);
for (int i = 1; i <= m; i++)
{
f >> op >> x >> y;
if (op == 0)
{
MAX = 0;
query(1, 1, n, x, y);
g << MAX << '\n';
}
if (op == 1)
{
update(1, 1, n, x, y);
}
}
}
int main()
{
rezolvare();
return 0;
}