//
// Created by Vlad Nitu on 11.02.2023.
//
#include <bits/stdc++.h>
using namespace std;
#define NMAX (int)(100001)
#define INF (int)(1e9)
#define ll long long
#define mkp make_pair
#define mkt make_tuple
#define lsb(x) (x & -x)
void __print(int x) { cerr << x; }
void __print(long x) { cerr << x; }
void __print(long long x) { cerr << x; }
void __print(unsigned x) { cerr << x; }
void __print(unsigned long x) { cerr << x; }
void __print(unsigned long long x) { cerr << x; }
void __print(float x) { cerr << x; }
void __print(double x) { cerr << x; }
void __print(long double x) { cerr << x; }
void __print(char x) { cerr << '\'' << x << '\''; }
void __print(const char *x) { cerr << '\"' << x << '\"'; }
void __print(const string &x) { cerr << '\"' << x << '\"'; }
void __print(bool x) { cerr << (x ? "true" : "false"); }
template<typename T, typename V, typename W>
void __print(const std::tuple<T, V, W> &x) {
cerr << '{';
__print(std::get<0>(x));
cerr << ',';
__print(std::get<1>(x));
cerr << ',';
__print(std::get<2>(x));
cerr << '}';
}
template<typename T, typename V>
void __print(const pair<T, V> &x) {
cerr << '{';
__print(x.first);
cerr << ',';
__print(x.second);
cerr << '}';
}
template<typename T>
void __print(const T &x) {
int f = 0;
cerr << '{';
for (auto &i: x) cerr << (f++ ? "," : ""), __print(i);
cerr << "}";
}
void _print() { cerr << "]\n"; }
template<typename T, typename... V>
void _print(T t, V... v) {
__print(t);
if (sizeof...(v)) cerr << ", ";
_print(v...);
}
#ifndef ONLINE_JUDGE
#define dbg(x...) cerr << "[" << #x << "] = ["; _print(x)
#else
#define dbg(x...)
#endif
struct hash_pair {
template<class T1, class T2>
size_t operator()(const pair<T1, T2> &p) const {
auto hash1 = hash<T1>{}(p.first);
auto hash2 = hash<T2>{}(p.second);
if (hash1 != hash2) {
return hash1 ^ hash2;
}
return hash1;
}
};
struct hash_tuple {
size_t operator()(const tuple<int, int, int> &x) const {
return hash<long long>()(
((long long) std::get<1>(x) ^ (((long long) std::get<2>(x)) ^ (long long) std::get<2>(x))) << 32);
}
};
int T, N, Q;
int lo[4 * NMAX + 1], hi[4 * NMAX + 1], mx[4 * NMAX + 1], delta[4 * NMAX + 1];
int v[NMAX];
void build(int i, int a, int b) { // Initialise SegmentTree
lo[i] = a;
hi[i] = b;
if (a == b)
return;
int mid = (a + b) / 2;
build(2 * i, a, mid);
build(2 * i + 1, mid + 1, b);
}
// `prop` and `update` -> template for SegmentTree that need to be modified depending on the task (min, max, sum, etc.)
int prop(int i) { // Lazy propagation of Segment Tree => push changes down to children
delta[2 * i] += delta[i];
delta[2 * i + 1] += delta[i];
delta[i] = 0;
}
void update(int i) { // Aggregate update function
mx[i] = max(mx[2 * i] + delta[2 * i], mx[2 * i + 1] + delta[2 * i + 1]);
}
void increment(int i, int a, int b, int val) {
if (b < lo[i] || hi[i] < a) // Outside the range [a,b] I'm updating
return;
if (a <= lo[i] &&
hi[i] <= b) { // [a,b] (interval I'm trying to cover) completely covers current node ([lo[i], hi[i]])
// Completely covering the subtree
delta[i] += val;
return;
}
// Partial cover case
prop(i); // Push change down to children before recursing
increment(2 * i, a, b, val);
increment(2 * i + 1, a, b, val);
update(i); // Store aggregate maximum of the entire subtree
}
void increment(int a, int b, int val) { // UPDATE: Increment all values in range [a, b] by `val`
increment(1, a, b, val);
}
int maximum(int i, int a, int b) {
if (b < lo[i] || a > hi[i]) // Outside range
return -INT_MAX;
if (a <= lo[i] && b >= hi[i]) // Entirely covering the node
return mx[i] + delta[i];
// Partial cover case
prop(i);
int maxLeft = maximum(2 * i, a, b);
int maxRight = maximum(2 * i + 1, a, b);
update(i);
return max(maxLeft, maxRight);
}
int maximum(int a, int b) { // QUERY: Maximum element in range [a, b]
return maximum(1, a, b);
}
int task, a, b, x;
int main() {
freopen("arbint.in", "r", stdin);
freopen("arbint.out", "w", stdout);
cin >> N >> Q;
build(1, 1, N);
for (int i = 1; i <= N; ++i)
{
cin >> x;
increment(i, i, x);
}
// cout << '\n';
//
// for (int i = 0; i <= 10 ;++i)
// cout << mx[i] << ' ';
while (Q --) {
cin >> task >> a >> b;
if (task == 0) {
cout << maximum(a, b) << '\n';
}
else
{
int cur_val = maximum(a, a);
increment(a, a, -cur_val + b); // v[a] = b
}
}
return 0;
}