#include <iostream>
#include <fstream>
#include <algorithm>
#include <vector>
#include <stack>
#include <queue>
using namespace std;
ifstream fin("arbint.in");
ofstream fout("arbint.out");
#define cin fin
#define cout fout
struct node_
{
int left, right, val;
node_ *leftChild, *rightChild;
node_()
{
this->leftChild = NULL;
this->rightChild = NULL;
this->val = 0;
}
void operator=(node_ x)
{
this->left = x.left;
this->right = x.right;
this->val = x.val;
this->leftChild = x.leftChild;
this->rightChild = x.rightChild;
}
};
struct segmentTree_
{
node_ *root_;
segmentTree_();
segmentTree_(vector<int>& elements);
node_* insertNode(node_ *location, bool leftRight, node_ val);
void build(vector<int>& elements);
void build_(node_* node, vector<int>& elements);
void clear();
void update(int index, int val);
void update_(node_* node, int index, int val);
int query(int left, int right);
int query_(node_* node, int left, int right);
};
node_ makeNode(int left, int right, int val = 0, node_ *leftChild = NULL, node_ *rightChild = NULL);
int main()
{
int n, q;
vector<int> elements;
segmentTree_ segmentTree;
cin >> n >> q;
elements.resize(n);
for(int i = 0; i < n; i++)
{
cin >> elements[i];
}
segmentTree.build(elements);
for(int i = 0, queryType, a, b; i < q; i++)
{
cin >> queryType >> a >> b;
if(queryType == 0)
{
a--;
b--;
cout << segmentTree.query(a, b) << '\n';
}
else
{
a--;
segmentTree.update(a, b);
}
}
return 0;
}
node_ makeNode(int left, int right, int val, node_ *leftChild, node_ *rightChild)
{
node_ temp;
temp.left = left;
temp.right = right;
temp.val = val;
temp.leftChild = leftChild;
temp.rightChild = rightChild;
return temp;
}
segmentTree_::segmentTree_()
{
this->root_ = NULL;
}
segmentTree_::segmentTree_(vector<int>& elements)
{
this->root_ = NULL;
this->build(elements);
}
node_* segmentTree_::insertNode(node_ *location, bool leftRight, node_ val)
{
node_* newNode = new node_;
*newNode = val;
if(leftRight == 0)
{
location->leftChild = newNode;
}
else
{
location->rightChild = newNode;
}
return newNode;
}
void segmentTree_::build(vector<int>& elements)
{
if(elements.size() == 0)
return;
this->clear();
this->root_ = new node_;
this->root_->left = 0;
this->root_->right = elements.size() - 1;
this->build_(this->root_, elements);
}
void segmentTree_::build_(node_* node, vector<int>& elements)
{
if(node->left == node->right)
{
node->val = elements[node->left];
}
else
{
int middle = (node->left + node->right) / 2;
insertNode(node, 0, makeNode(node->left, middle));
insertNode(node, 1, makeNode(middle + 1, node->right));
build_(node->leftChild, elements);
build_(node->rightChild, elements);
node->val = max(node->leftChild->val, node->rightChild->val);
}
}
void segmentTree_::clear()
{
if(this->root_ == NULL)
{
return;
}
queue<node_*> bfs;
node_* node;
bfs.push(this->root_);
while(!bfs.empty())
{
node = bfs.front();
bfs.pop();
if(node->leftChild != NULL)
{
bfs.push(node->leftChild);
}
if(node->rightChild != NULL)
{
bfs.push(node->rightChild);
}
delete node;
}
this->root_ = NULL;
}
void segmentTree_::update(int index, int val)
{
if(this->root_ != NULL)
{
this->update_(this->root_, index, val);
}
}
void segmentTree_::update_(node_* node, int index, int val)
{
if(node->left == node->right)
{
node->val = val;
}
else
{
int middle = (node->left + node->right) / 2;
if(index <= middle)
{
update_(node->leftChild, index, val);
}
else
{
update_(node->rightChild, index, val);
}
node->val = max(node->leftChild->val, node->rightChild->val);
}
}
int segmentTree_::query(int left, int right)
{
if(this->root_ == NULL)
{
return -2;
}
return query_(this->root_, left, right);
}
int segmentTree_::query_(node_* node, int left, int right)
{
if(left <= node->left && node->right <= right)
{
return node->val;
}
else if(node->right >= left && node->left <= right)
{
return max(query_(node->leftChild, left, right), query_(node->rightChild, left, right));
}
return -1;
}