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