#include <bits/stdc++.h>
using namespace std;
ifstream in("arbint.in");
ofstream out("arbint.out");
const int MIN_VALUE = -1e6;
void buildTree(int v[], int tree[], int left, int right, int poz)
{
if (left == right)
{
//we reached a leaf
tree[poz] = v[left];
return;
}
int mid = left + (right - left) / 2;
//build left child
buildTree(v, tree, left, mid, 2 * poz + 1);
//build right child
buildTree(v, tree, mid + 1, right, 2 * poz + 2);
//get maximum in parent node
tree[poz] = max(tree[2 * poz + 1], tree[2 * poz + 2]);
}
void updateTree(int v[], int tree[],
int left, int right, int poz, int updatePoz, int val)
{
if (left == right)
{
//we reached a leaf
//cand ajungem la frunza, ajungem fix
//la frunza care contine pozitia care ne intereseaza
//de ce?
//mereu mergem pe intervalul unde este pozitia noastra
//pana cand ajungem la intervalul cu o singura pozitie
tree[poz] = val;
return;
}
//just follow up with the updates
int mid = left + (right - left) / 2;
//check what part needs to be updated
if (updatePoz <= mid)
{
//build left child
updateTree(v, tree, left, mid, 2 * poz + 1,
updatePoz, val);
}
else
{
//build right child
updateTree(v, tree, mid + 1, right, 2 * poz + 2,
updatePoz, val);
}
//get maximum in parent node
tree[poz] = max(tree[2 * poz + 1], tree[2 * poz + 2]);
}
int treeRangeMinimumQuerry(int v[], int tree[],
int left, int right, int poz, int leftQuery, int rightQuery)
{
// total overlap
//EX: daca ai intervalul [0,5]
//tu ai ajuns la [0,4]
//[0,4] e inclus in [0,5] deci poti sa iei direct minimul
if (leftQuery <= left && rightQuery >= right)
return tree[poz];
// no overlap
//EX: ai intervalul [2,10]
// iar tu ai ajuns la [1, 1]
// 1 nu e inclus in intervalul tau
// deci nu te intereseaza
// returnezi o valoare care nu poate fi rezultat
if (leftQuery > right || rightQuery < left)
return MIN_VALUE;
// partial overlap
//EX: daca ai intervalul [0, 6]
// tu ai ajuns la [3, 7]
// [3, 7] nu e inclus in intervalul tau este,
// dar [0, 3] este, la fel si in dreapta [4, 6] este
// cauti in stanga in [0, 3] si in dreapta in [4, 7]
int mid = left + (right - left) / 2;
return max(treeRangeMinimumQuerry(v, tree, left,
mid, 2 * poz + 1, leftQuery, rightQuery),
treeRangeMinimumQuerry(v, tree, mid + 1,
right, 2 * poz + 2, leftQuery, rightQuery));
}
int calculateTreeDimension(int n)
{
//pentru fiecare pereche de numere ai cate un rezultat
//ar veni practic n + n / 2 + n / 4 + ... 1
// suma progresiei geometrice este egala cu
// 2 ^ (nr termeni) - 1
// daca n e putere de 2 o sa acoperi tot tree-ul
// deci numarul de termeni e log2(n) + 1
// daca nu trebuie creat un nivel in plus cu frunze cu val
// maxima, ca sa ai unde pune toate valorile
int lg = log2(n);
if ((1 << lg) == n)
return (1 << (lg + 1)) - 1;
else
return (1 << (lg + 2)) - 1;
}
int main()
{
int n, m;
in >> n >> m;
int v[n];
for (int i = 0; i < n; i++)
in >> v[i];
int treeSize = calculateTreeDimension(n);
int tree[treeSize];
for (int i = 0; i < treeSize; i++)
tree[i] = MIN_VALUE;
buildTree(v, tree, 0, n - 1, 0);
while (m--)
{
int c, x, y;
in >> c >> x >> y;
x--;
y--;
if (c == 0)
out << treeRangeMinimumQuerry(v, tree, 0, n - 1, 0,
x, y) << endl;
else
updateTree(v, tree, 0, n - 1, 0, x, y + 1);
}
return 0;
}