#include <bits/stdc++.h>
using namespace std;
const int maxN = 1e5+2;
const int INF = 1e9+20;
int idx, value;
void update(int *st, int left, int right, int node) {
if(left == right) {
st[node] = value;
return;
}
int mid = (right - left)/2 + left;
if(idx <= mid)
update(st, left, mid, node*2+1);
else update(st, mid+1, right, node*2+2);
st[node] = max(st[node*2+1], st[2*node+2]);
}
int query(int* st, int left, int right, int a, int b, int node) {
// if segment of current node is inside the query range then return node value
if (a <= left && right <= b)
return st[node];
if (left > b || right < a)
return -INF;
int mid = (right - left)/2 + left;
return max(query(st, left, mid, a, b, node*2+1),
query(st, mid+1, right, a, b, node*2+2));
}
int auxConstructST(int a[], int left, int right, int *st, int node){
if(left == right) {
st[node] = a[left];
return a[left];
}
int mid = (right - left)/2 + left;
st[node] = max(auxConstructST(a, left, mid, st, node*2+1),
auxConstructST(a, mid+1, right, st, node*2+2));
return st[node];
}
// depth 2^(ceil(log2(#leaves)))
// ST = full binary tree --> internal nodes = leaves-1
int *constructST(int a[], int n) {
int height = (int)(ceil(log2(n)));
int size = 2 * (int)pow(2, height) - 1;
int *root = new int[size+2];
//printf("%d%d\n", height, size);
auxConstructST(a, 0, n-1, root, 0);
return root;
}
int main() {
int n, m;
int a[maxN];
scanf("%d%d", &n, &m);
for (int i = 0; i < n; ++ i)
scanf("%d", &a[i]);
int *root = constructST(a, n);
for (; m > 0; -- m) {
int qType, a, b;
scanf("%d%d%d", &qType, &a, &b);
if(qType == 0)
printf("%d\n", query(root, 0, n-1, a-1, b-1, 0));
else {
idx = a-1;
value = b;
update(root, 0, n-1, 0);
}
}
return 0;
}