#include <vector>
#include <iostream>
int update(std::vector<int>& tree, int index, int value, int start, int end) {
int li = start, ls = end, poz = 0;
if (tree[poz] < value) {
tree[poz] = value;
}
while ((li < ls)) {
int m = (li + ls) / 2;
if (index <= m) {
ls = m;
poz = 2 * poz + 1;
if (tree[poz] < value) tree[poz] = value;
}
else{
li = m + 1;
poz = 2 * poz + 2;
if (tree[poz] < value) tree[poz] = value;
}
}
tree[poz] = value;
while (poz) {
int t = (poz - 1) / 2;
tree[t] = std::max(tree[2 * t + 1], tree[2 * t + 2]);
poz = (poz - 1) / 2;
}
return 0;
}
void query(std::vector<int>& tree, int index, int start, int finish, int left, int right, int& maxim) {
if ((start <= left) && (right <= finish)) {
maxim = std::max(maxim, tree[index]);
return;
}
int m = (left + right) / 2;
if (start <= m) query(tree, 2 * index + 1, start, finish, left, m, maxim);
if (finish >= m + 1) query(tree, 2 * index + 2, start, finish, m + 1, right, maxim);
}
int query(std::vector<int>& tree, int begin, int end, int size) {
int maxim = 0;
query(tree, 0, begin, end, 0, size, maxim);
return maxim;
}
#ifndef TESTING
int main() {
FILE *f = fopen("arbint.in", "r");
FILE *g = fopen("arbint.out", "w");
int N, M, x;
long long n = 0;
fscanf(f, "%d %d", &N, &M);
int j = 1;
while (j < 2 * N) {
n += j;
j *= 2;
}
std::vector<int> a(n);
for (int i = 0; i < N; ++i) {
fscanf(f, "%d", &x);
update(a, i, x, 0, N - 1);
}
for (int i = 0; i < M; ++i) {
int x, y, z;
fscanf(f, "%d %d %d", &x, &y, &z);
if (x) {
update(a, y - 1, z, 0, N - 1);
}
else {
fprintf(g, "%d\n", query(a, y - 1, z - 1, N - 1));
}
}
fclose(f);
fclose(g);
return 0;
}
#endif