#include <algorithm>
#include <string>
#include <iostream>
#include <cstdio>
#include <vector>
#include <set>
#include <map>
#include <queue>
using namespace std;
#ifdef INFOARENA
#define TEST 0
#else
#define TEST 1
#endif
class IntervalTree {
public:
IntervalTree(const vector<int> &values) {
num_values_ = values.size();
for (int i = 0; i < values.size(); ++i) {
// Construct segments
UpdateInternal(0, 0, num_values_ - 1, i, values[i]);
}
}
int QueryMax(int left_pos, int right_pos) {
int answer = 0;
QueryMaxInternal(0, left_pos, right_pos, 0, num_values_ - 1, answer);
return answer;
}
void QueryMaxInternal(int node, int left_pos, int right_pos, int left_segment_pos, int right_segment_pos, int &answer) {
if (left_pos <= left_segment_pos && right_segment_pos <= right_pos) {
// This segment fits into searched positions
answer = max(answer, segments_[node]);
return;
}
int middle_segment_pos = (left_segment_pos + right_segment_pos) / 2;
if (left_pos <= middle_segment_pos) {
// Need to collect data from the overlapping part
QueryMaxInternal(2 * node + 1, left_pos, right_pos, left_segment_pos, middle_segment_pos, answer);
}
if (right_pos > middle_segment_pos) {
QueryMaxInternal(2 * node + 2, left_pos, right_pos, middle_segment_pos + 1, right_segment_pos, answer);
}
}
void Update(int pos_to_update, int value) {
UpdateInternal(0, 0, num_values_ - 1, pos_to_update, value);
}
void UpdateInternal(int node, int left_pos, int right_pos, int pos_to_update, int value) {
if (left_pos == right_pos) {
// Single element segment
if (node >= segments_.size()) {
// Assure also that the right subsegment will fit.
segments_.resize(2 * node + 2);
}
segments_[node] = value;
return;
}
int middle_pos = (left_pos + right_pos) / 2;
if (pos_to_update <= middle_pos) {
UpdateInternal(2 * node + 1, left_pos, middle_pos, pos_to_update, value);
} else {
UpdateInternal(2 * node + 2, middle_pos + 1, right_pos, pos_to_update, value);
}
// Update maximum on this interval
segments_[node] = max(segments_[2 * node + 1], segments_[2 * node + 2]);
}
private:
vector<int> segments_;
int num_values_;
};
int main() {
freopen("arbint.in","r",stdin);
freopen("arbint.out","w", stdout);
int num_values, num_queries;
scanf("%d %d", &num_values, &num_queries);
vector<int> values;
values.resize(num_values);
for (int i = 0; i < num_values; ++i) {
scanf("%d", &values[i]);
}
IntervalTree *instance = new IntervalTree(values);
int type, left_pos, right_pos;
for (int i = 0; i < num_queries; ++i) {
scanf("%d %d %d", &type, &left_pos, &right_pos);
if (type == 0) {
printf("%d\n", instance->QueryMax(left_pos - 1, right_pos - 1));
} else {
int pos_to_update = left_pos;
int value_for_update = right_pos;
instance->Update(pos_to_update - 1, value_for_update);
}
}
return 0;
}