#include <fstream>
#include <cmath>
using namespace std;
const int INF = 0x3f3f3f3f, MaxN = (1 << 17) + 5;
ifstream cin("arbint.in");
ofstream cout("arbint.out");
int SgTree[2 * MaxN], v[MaxN];
int n, q, abs_right;
inline int LfSon(int node) {
return 2 * node;
}
inline int RgSon(int node) {
return 2 * node + 1;
}
inline void BuildTree(int l = 1, int r = abs_right, int node = 1) {
if(l == r) {
SgTree[node] = v[l];
return;
}
int med = (l + r) / 2;
BuildTree(l, med, LfSon(node));
BuildTree(med + 1, r, RgSon(node));
SgTree[node] = max(SgTree[LfSon(node)], SgTree[RgSon(node)]);
}
void Update(int pos, int val, int l = 1, int r = abs_right, int node = 1) {
if(l == r) {
SgTree[node] = val;
return;
}
int med = (l + r) / 2;
if(pos <= med) {
Update(pos, val, l, med, LfSon(node));
}
else {
Update(pos, val, med + 1, r, RgSon(node));
}
SgTree[node] = max(SgTree[LfSon(node)], SgTree[RgSon(node)]);
}
int Query(int srch_l, int srch_r, int l = 1, int r = abs_right, int node = 1) {
if(srch_l <= l and srch_r >= r) {
return SgTree[node];
}
int med = (l + r) / 2;
int ans = 0;
if(srch_l <= med) {
int nxt_qry = Query(srch_l, srch_r, l, med, LfSon(node));
ans = max(ans, nxt_qry);
}
if(srch_r > med) {
int nxt_qry = Query(srch_l, srch_r, med + 1, r, RgSon(node));
ans = max(ans, nxt_qry);
}
return ans;
}
int main() {
cin >> n >> q;
for(int i = 1; i <= n; ++i) {
cin >> v[i];
}
int log2n = log2(n);
log2n += ((1 << log2n) < n);
abs_right = (1 << log2n);
BuildTree();
for(int i = 1; i <= q; ++i) {
int a, b;
bool type;
cin >> type >> a >> b;
if(type == 1) {
Update(a, b);
}
else {
cout << Query(a, b) << '\n';
}
}
return 0;
}
/*#include <fstream>
#include <cmath>
#define NMAX 100005
#define SQROOTMAX 320
#define INF 0x3f3f3f3f
using namespace std;
ifstream cin("arbint.in");
ofstream cout("arbint.out");
class SegmentPosition {
public:
int left, right;
};
SegmentPosition segm_pos[SQROOTMAX];
int n, q, sqroot, v[NMAX], segm[SQROOTMAX];
inline void update(int pos, int val) {
int pos_l, pos_r, curr_intv;
if(pos % sqroot != 0) {
pos_l = pos / sqroot * sqroot + 1;
pos_r = pos_l + sqroot - 1;
curr_intv = pos / sqroot + 1;
}
else {
pos_l = (pos / sqroot - 1) * sqroot + 1;
pos_r = pos_l + sqroot - 1;
curr_intv = pos / sqroot;
}
v[pos] = val;
segm[curr_intv] = 0;
for(int i = pos_l; i <= pos_r; ++i) {
segm[curr_intv] = max(segm[curr_intv], v[i]);
}
}
inline int query(int l_qr, int r_qr) {
int ans = 0, l = INF, r = -1;
for(int i = 1; i <= sqroot + (n % sqroot != 0); ++i) {
if(l_qr <= segm_pos[i].left and r_qr >= segm_pos[i].right) {
if(l > segm_pos[i].left) {
l = segm_pos[i].left;
}
if(r < segm_pos[i].right) {
r = segm_pos[i].right;
}
ans = max(ans, segm[i]);
}
}
if(l == INF and r == -1) {
l = r_qr;
r = r_qr + 1;
}
for(int i = l_qr; i <= l; ++i) {
ans = max(ans, v[i]);
}
for(int i = r; i <= r_qr; ++i) {
ans = max(ans, v[i]);
}
return ans;
}
int main() {
cin >> n >> q;
for(int i = 1; i <= n; ++i) {
cin >> v[i];
}
sqroot = sqrt(n);
for(int i = 1; i <= sqroot + 1; ++i) {
segm_pos[i].left = (i - 1) * sqroot + 1;
segm_pos[i].right = i * sqroot;
for(int j = segm_pos[i].left; j <= segm_pos[i].right; ++j) {
segm[i] = max(segm[i], v[j]);
}
}
if(n % sqroot == 0) {
segm[sqroot + 1] = -1;
}
for(int i = 1; i <= q; ++i) {
int a, b;
bool type;
cin >> type >> a >> b;
if(type == 1) {
update(a, b);
}
else {
cout << query(a, b) << '\n';
}
}
return 0;
}
*/