/*
example for segment trees ( arbori de intervale):
[ Node 1 ]
Tracks Max of [1-4]
Value: Max(8,5) = 8
/ \
/ \
[ Node 2 ] [ Node 3 ]
Tracks [1-2] Tracks [3-4]
Value: Max(2,8)=8 Value: Max(5,3)=5
/ \ / \
/ \ / \
Node 4 Node 5 Node 6 Node 7
Tracks[1] Tracks[2] Tracks[3] Tracks[4]
Val: 2 Val: 8 Val: 5 Val: 3
*/
#include <stdio.h>
#include <stdlib.h>
#define MAXN 100005
int tree[4 * MAXN];
int maxi(int a , int b){
return a > b ? a : b;
}
void build(int node, int l, int r, int *a) {
if (l == r) {
tree[node] = a[l];
return;
}
int mid = (l + r) / 2;
build(2 * node, l, mid, a);
build(2 * node + 1, mid + 1, r, a);
tree[node] = maxi(tree[2 * node], tree[2 * node + 1]);
}
void update(int node, int l, int r, int pos, int val) {
if (l == r) {
tree[node] = val;
return;
}
int mid = (l + r) / 2;
if (pos <= mid)
update(2 * node, l, mid, pos, val);
else
update(2 * node + 1, mid + 1, r, pos, val);
tree[node] = maxi(tree[2 * node], tree[2 * node + 1]); // after the base case, it goes back and recomputes the values
}
int query(int node, int l, int r, int ql, int qr) {
if (ql <= l && r <= qr)
return tree[node];
int mid = (l + r) / 2;
int res = 0;
if (ql <= mid)
res = maxi(res, query(2 * node, l, mid, ql, qr)); // go one level deeper in the tree, on left side
if (qr > mid)
res = maxi(res, query(2 * node + 1, mid + 1, r, ql, qr)); // one level deeper on right side
return res;
}
int main() {
FILE *fin = fopen("arbint.in", "r");
FILE *fout = fopen("arbint.out", "w");
int N,M;
fscanf(fin, "%d %d", &N, &M);
int *a = malloc((N + 1) * sizeof(int));
for (int i = 1; i <= N; i++)
fscanf(fin, "%d", &a[i]);
build(1, 1, N, a);
for (int i = 0; i < M; i++) {
int op, x, y;
fscanf(fin, "%d %d %d", &op, &x, &y);
if (op == 0)
fprintf(fout, "%d\n", query(1, 1, N, x, y));
else
update(1, 1, N, x, y);
}
free(a);
fclose(fin);
fclose(fout);
return 0;
}