#include<bits/stdc++.h>
using namespace std;
const int NMAX = 1e5 + 5;
int v[NMAX], aint[NMAX * 4];
void build_tree(int node, int left, int right){
if(left == right){
aint[node] = v[left];
return;
}
int middle = (left + right) / 2;
build_tree(2 * node, left, middle);
build_tree(2 * node + 1, middle + 1, right);
aint[node] = max(aint[2 * node], aint[2 * node + 1]);
}
void update_recursiv(int node, int left, int right, int position, int new_value){
if(left == right){
aint[node] = new_value;
return;
}
int middle = (left + right) / 2;
if(position <= middle)
update_recursiv(2 * node, left, middle, position, new_value);
else
update_recursiv(2 * node + 1, middle + 1, right, position, new_value);
aint[node] = max(aint[2 * node], aint[2 * node + 1]);
}
void update(int position, int new_value, int n){
update_recursiv(1, 1, n, position, new_value);
}
int query_recursiv(int node, int left, int right, int query_left, int query_right){
if(left > right || query_left > query_right) return 0;
if(left == query_left && right == query_right)
return aint[node];
int middle = (left + right) / 2;
if(query_right <= middle)
return query_recursiv(2 * node, 1, middle, query_left, query_right);
else if(query_left > middle)
return query_recursiv(2 * node + 1, middle + 1, right, query_left, query_right);
return max(query_recursiv(2 * node, left, middle, query_left, middle), query_recursiv(2 * node + 1, middle + 1, right, middle + 1, query_right));
}
int query(int left, int right, int n){
return query_recursiv(1, 1, n, left, right);
}
int main(){
freopen("arbint.in", "r", stdin);
freopen("arbint.out", "w", stdout);
int n, queries;
scanf("%d %d", &n, &queries);
for(int i = 1; i <= n; i++){
scanf("%d", &v[i]);
}
build_tree(1, 1, n);
for(; queries > 0; queries--){
int operation, a, b;
scanf("%d %d %d", &operation, &a, &b);
if(operation == 0){
printf("%d\n", query(a, b, n));
}
else if(operation == 1){
update(a, b, n);
}
}
return 0;
}