/**
* In this code we have a very large array called arr, and very large set of operations
* Operation #1: Increment the elements within range [i, j] with value val
* Operation #2: Get max element within range [i, j]
* Build tree: build_tree(1, 0, N-1)
* Update tree: update_tree(1, 0, N-1, i, j, value)
* Query tree: query_tree(1, 0, N-1, i, j)
*/
#include<fstream>
#include<algorithm>
#include<string.h>
#include<math.h>
using namespace std;
#define N 100000
#define MAX (4*N+64)
#define inf 0x7fffffff
ifstream cin("arbint.in");
ofstream cout("arbint.out");
int arr[N];
int tree[MAX];
void build_tree(int node, int a, int b) {
if(a > b) return;
if(a == b) {
tree[node] = arr[a];
return;
}
build_tree(node*2, a, (a+b)/2);
build_tree(node*2+1, 1+(a+b)/2, b);
tree[node] = max(tree[node*2], tree[node*2+1]);
}
void update_tree(int node, int a, int b, int i, int j, int value) {
if(a > b || a > j || b < i)
return;
if(a == b) {
tree[node] = value;
return;
}
update_tree(node*2, a, (a+b)/2, i, j, value);
update_tree(1+node*2, 1+(a+b)/2, b, i, j, value);
tree[node] = max(tree[node*2], tree[node*2+1]);
}
int query_tree(int node, int a, int b, int i, int j) {
if(a > b || a > j || b < i) return -inf;
if(a >= i && b <= j)
return tree[node];
int q1 = query_tree(node*2, a, (a+b)/2, i, j);
int q2 = query_tree(1+node*2, 1+(a+b)/2, b, i, j);
int res = max(q1, q2);
return res;
}
int n, m;
int main() {
cin>>n>>m;
for(int i=0;i<n;i++) cin>>arr[i];
build_tree(1, 0, n-1);
while (m){
int w, u, v;
cin>>w>>u>>v;
if (!w) cout<<query_tree(1, 0, n-1, u-1, v-1)<<endl;
else update_tree(1, 0, n-1, u-1, u-1, v); m--;
}
}