#include <stdio.h>
#include <vector>
#include <iostream>
using namespace std;
int n, m, maxpoz = 0;
vector<int> arb;
vector<int> pozitii;
void solve();
void build(int, int, int);
void update(int);
int query(int, int);
inline int max(int, int);
int main()
{
solve();
return 0;
}
void solve()
{
int i, x, y, z;
FILE *fin = fopen("arbint.in", "r");
FILE *fout = fopen("arbint.out", "w");
fscanf (fin, "%d%d", &n, &m);
arb.resize(4 * n + 200);
pozitii.resize(n + 1);
build(1, n, 1);
for (i = 1; i <= n; ++i)
{
fscanf(fin, "%d", &arb[pozitii[i]]);
update(pozitii[i]);
}
for (i = 1; i <= m; ++i)
{
fscanf(fin, "%d%d%d", &x, &y, &z);
if (x == 1)
{
arb[pozitii[y]] = z;
update(pozitii[y]);
}
else
{
fprintf (fout, "%d\n", query(pozitii[y], pozitii[z]));
}
}
fclose(fin);
fclose(fout);
}
int query(int poz1, int poz2)
{
int max1 = arb[poz1], max2 = arb[poz2];
/* for (int i = 1; i <= maxpoz; ++i)
{
printf ("%d ", arb[i]);
}
printf ("\nAflu maximul cuprins intre %d si %d:\n", arb[poz1], arb[poz2]);
*/ while (poz1 / 2 != poz2 / 2)
{
// printf ("poz1: %d si poz2: %d\tmax1: %d si max2: %d\n", poz1, poz2, max1, max2);
if (poz1 > poz2)
{
if (poz1 % 2)
{
poz1 /= 2;
}
else
{
max1 = max(arb[poz1], arb[poz1+1]);
poz1 /= 2;
}
}
else
{
if (poz2 % 2 == 0)
{
poz2 /= 2;
}
else
{
max2 = max(arb[poz2-1], arb[poz2]);
poz2 /= 2;
}
}
}
// printf ("poz1: %d si poz2: %d\tmax1: %d si max2: %d\n\n", poz1, poz2, max1, max2);
return max(max1, max2);
}
void build(int st, int dr, int poz)
{
if (poz > maxpoz) maxpoz = poz;
if (st == dr)
{
pozitii[st] = poz;
return;
}
int mid = (st + dr) / 2;
build(st, mid, poz * 2);
build(mid + 1, dr, poz * 2 + 1);
}
void update(int poz)
{
int t;
for (t = poz / 2; t; t /= 2)
{
arb[t] = max (arb[t*2], arb[t*2+1]);
}
}
inline int max(int x, int y)
{
return (x > y ? x : y);
}