#include<fstream>
#include <limits>
#define N 100005
#define TREESIZE 262150
using namespace std;
ifstream f("arbint.in");
ofstream g("arbint.out");
bool isInsideInterval(int pos, int left, int right)
{
if (pos >= left && pos <= right)
{
return true;
}
return false;
}
int queryTree(int *Tree, int lt, int rt, int position, int qlt, int qrt)
{
if (isInsideInterval(lt, qlt, qrt) && isInsideInterval(rt, qlt, qrt))
{
return Tree[position];
}
int mid = (lt + rt) / 2;
int leftVal = -numeric_limits<int>::max();
int rightVal = -numeric_limits<int>::max();
if (qlt <= mid && qrt >= lt)
{
leftVal = queryTree(Tree, lt, mid, position * 2, qlt, qrt);
}
if (qrt >= mid + 1 && qlt <= rt)
{
rightVal = queryTree(Tree, mid + 1, rt, position * 2 + 1, qlt, qrt);
}
return max(leftVal, rightVal);
}
void updateTree(int *A, int *Tree, int lt, int rt, int position, int updateIndex)
{
if (lt == rt && lt == updateIndex)
{
Tree[position] = A[updateIndex];
return;
}
int mid = (lt + rt) / 2;
if (updateIndex <= mid)
{
updateTree(A, Tree, lt, mid, 2 * position, updateIndex);
}
else
{
updateTree(A, Tree, mid + 1, rt, 2 * position + 1, updateIndex);
}
Tree[position] = max(Tree[2 * position], Tree[2 * position + 1]);
}
void buildTree(int *A, int *Tree, int lt, int rt, int position)
{
if (lt == rt)
{
Tree[position] = A[lt];
return;
}
int mid = (lt + rt) / 2;
buildTree(A, Tree, lt, mid, 2 * position);
buildTree(A, Tree, mid + 1, rt, 2 * position + 1);
Tree[position] = max(Tree[2 * position], Tree[2 * position + 1]);
}
int A[N];
int Tree[TREESIZE];
int main()
{
int n, m;
f >> n >> m;
for(int i = 1; i <= n; i++)
{
f >> A[i];
}
buildTree(A, Tree, 1, n, 1);
for(int i = 1; i <= m; i++)
{
int codop, a, b;
f >> codop >> a >> b;
if (codop == 0)
{
g << queryTree(Tree, 1, n, 1, a, b) << "\n";
}
if (codop == 1)
{
A[a] = b;
updateTree(A, Tree, 1, n, 1, a);
}
}
return 0;
}