// ArboriIntervale.cpp : Defines the entry point for the console application.
//
#include <stdio.h>
#define max(a,b) (a)>(b) ? (a) : (b)
struct st
{
unsigned long long v;
struct st *p, *r;
};
int main(int argc, char* argv[])
{
struct st s[165537], *level[20],*p;
unsigned long long n, m, i, j, a, b, s_index, max_level = 0, first, complete = 0, clev, maxv;
if (!freopen("arbint.in", "r", stdin))
return -1;
freopen("arbint.out", "w", stdout);
scanf("%llu", &n);
scanf("%llu", &m);
for (s_index = 0; s_index < n; ++s_index)
{
scanf("%llu", &s[s_index].v);
}
level[max_level++] = &s[0];
first = 1;
while (!complete)
{
first = 1;
p = level[max_level - 1];
while (((p != level[max_level - 1]) && (p != (level[max_level - 1] + 1))) ||
(first))
{
if (p + 1 != level[max_level - 1])
s[s_index].v = max(p->v, (p + 1)->v);
else
s[s_index].v = p->v;
p->p = &s[s_index];
(p + 1)->p = &s[s_index];
s[s_index].r = p + 1;
if (first)
{
first = 0;
level[max_level++] = &s[s_index];
if ((p + 2 == level[max_level - 1]) || (p + 1 == level[max_level - 1]))
complete = 1;
}
p += 2;
++s_index;
}
}
--s_index;
--max_level;
for (i = 0; i < m; ++i)
{
scanf("%llu %llu %llu", &j, &a, &b);
--a;
if (j)
{
s[a].v = b;
p = &s[a];
complete = 0;
while ((p->p) && (!complete))
{
if ((p + 1)->p == p->p)
if (max((p + 1)->v, p->v) != p->p->v)
{
p = p->p;
p->v = max((p + 1)->v, p->v);
}
else
complete = 1;
if ((p - 1)->p == p->p)
if (max((p - 1)->v, p->v) != p->p->v)
{
p = p->p;
p->v = max((p - 1)->v, p->v);
}
else
complete = 1;
}
}
else
{
--b;
clev = 1;
maxv = s[a].v;
p = &s[a];
while (a < b)
{
if ((p->p == (p + 1)->p) &&
( a+ clev <= b))
{
maxv = max(maxv, p->p->v);
a += clev;
clev = clev * 2;
p = p->p;
}
else
{
if (a + clev <= b)
{
a += clev;
maxv = max(maxv, (p + 1)->v);
p = p + 1;
}
else
{
p = p->r;
clev = clev / 2;
}
}
}
printf("%llu\n", maxv);
}
}
return 0;
}