#include <bits/stdc++.h>
using namespace std;
ifstream fin("arbint.in");
ofstream fout("arbint.out");
class Arbore
{
protected:
int *aint;
int n;
public:
virtual int InitInt() {return 0;}
virtual int Merge(int a, int b){cout << "p\n";return a + b;}
void Init(int n)
{
this->n = n;
aint = new int[4 * n + 1];
for (int i = 0; i <= 4 * n; i++)
aint[i] = InitInt();
}
virtual void Build(int a[], int nod, int l, int r)
{
if (l == r)
{
aint[nod] = a[l];
return;
}
int mid = (l + r) / 2;
Build(a, 2 * nod, l, mid);
Build(a, 2 * nod + 1, mid + 1, r);
aint[nod] = Merge(aint[2 * nod], aint[2 * nod + 1]);
}
Arbore(){}
Arbore(int n){Init(n);}
Arbore(int a[], int n){Init(n); Build(a, 1, 1, n);}
void Update(int nod, int l, int r, int p, int x)
{
if (r < p || l > p) return;
if (l == r)
{
aint[nod] = x;
return;
}
int mid = (l + r) / 2;
Update(2 * nod, l, mid, p, x);
Update(2 * nod + 1, mid + 1, r, p, x);
aint[nod] = Merge(aint[2 * nod], aint[2 * nod + 1]);
}
int Query(int nod, int start, int end, int l, int r)
{
if (r < start || l > end) return InitInt();
if (start <= l && r <= end) return aint[nod];
int mid = (l + r) / 2;
int p1 = Query(2 * nod, start, end, l, mid);
int p2 = Query(2 * nod + 1, start, end, mid + 1, r);
return Merge(p1, p2);
}
};
class ArboreMax : public Arbore
{
public:
ArboreMax() {}
ArboreMax(int n) : Arbore(n) {}
ArboreMax(int a[], int n) : Arbore(a, n) {}
virtual int Merge(int a, int b) {return max(a, b);}
virtual int InitInt() {return -2e9;}
};
int a[100005], n;
ArboreMax aint;
int main()
{
int i, op, x, y, q;
fin >> n >> q;
for (i = 1; i <= n; i++)
fin >> a[i];
aint.Init(n);
aint.Build(a, 1, 1, n);
while (q--)
{
fin >> op >> x >> y;
if (op == 0) fout << aint.Query(1, x, y, 1, n) << "\n";
else aint.Update(1, 1, n, x, y);
}
return 0;
}