#include <fstream>
#include <algorithm>
#include <climits>
using namespace std;
ifstream in("arbint.in");
ofstream out("arbint.out");
#define MAX 100000
int v[MAX], tree[4 * MAX];
int N, M;
class SegTree
{
static void UpdateUtil(int node, int left, int right, int poz, int val)
{
if (left == right)
{
tree[node] = val;
return;
}
int mid = (left + right) / 2;
int leftc = node << 2 + 1;
int rightc = leftc + 1;
if (poz <= mid)
{
UpdateUtil(leftc, left, mid, poz, val);
}
else
{
UpdateUtil(rightc, mid + 1, right, poz, val);
}
tree[node] = max(tree[leftc], tree[rightc]);
}
static int QueryUtil(int node, int left, int right, int x, int y)
{
if (left >= x && right <= y)
{
return tree[node];
}
if (right < x || left > y)
{
return -INT_MAX;
}
int mid = (left + right) / 2;
int max_ = -INT_MAX;
if (mid >= x)
{
int leftc = node << 2 + 1;
max_ = max(max_, QueryUtil(leftc, left, mid, x, y));
}
if (y > mid)
{
int rightc = node << 2 + 1 + 1;
max_ = max(max_, QueryUtil(rightc, mid + 1, right, x, y));
}
return max_;
}
public:
static void BuildTree(int node, int left, int right)
{
if (left == right)
{
tree[node] = v[left];
return;
}
int mid = (left + right) / 2;
int leftc = node << 2 + 1;
int rightc = leftc + 1;
BuildTree(leftc, left, mid);
BuildTree(rightc, mid + 1, right);
tree[node] = max(tree[leftc], tree[rightc]);
}
static void Update(int poz, int value)
{
UpdateUtil(0, 0, N - 1, poz, value);
}
static int Query(int x, int y)
{
return QueryUtil(0, 0, N - 1, x, y);
}
};
int main()
{
in >> N >> M;
for (int i = 0; i < N; i++)
{
in >> v[i];
}
SegTree::BuildTree(0, 0, N-1);
for (int i = 0; i < M; i++)
{
int opt, a, b;
in >> opt >> a >> b;
if (opt == 0)
{
out << SegTree::Query(a - 1, b - 1) << endl;
}
else if (opt == 1)
{
SegTree::Update(a - 1, b);
}
}
}