/*少说话,多做事*/
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <vector>
#include <stack>
#include <sstream>
#include <map>
#include <set>
#include <queue>
#include <stdlib.h>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
const int SIZE=500005;
int a[SIZE];
struct segment
{
    int l,r;
    int ls,rs;//l最大前缀和 \ r最大后缀和
    int sum,dat; //sum为区间和,dat为最后的结果
}t[2000005];

void update(int p)
{
    int zuo = p<<1;
    int you = p<<1|1;
    /*更新p点的区间和 、最大前缀和 、最大后缀和 、最终的结果*/
    t[p].sum = t[you].sum + t[zuo].sum;                 //p点的sum值为两个子节点之和
    t[p].ls = max(t[zuo].ls , t[zuo].sum + t[you].ls);  //p点的最大前缀和是 max(左面的最大前缀和 , 右面的最大前缀和 + 左面的区间和)
    t[p].rs = max(t[you].rs , t[zuo].rs  + t[you].sum); //p点的最大后缀和是 max(右面的最大后缀和 ,左面的最大后缀和 + 右面的区间和)
    t[p].dat = max(t[zuo].dat , max(t[you].dat , t[zuo].rs+t[you].ls)); //左面的dat,右面的dat,以及左面的后缀加右面的前缀
}

void build(int p,int l,int r) //建树:当前节点编号,范围,[l,r]
{
    t[p].l=l; //当前节点的编号是l,
    t[p].r=r; //当前节点的编号是r,
    if(l==r)  //如果l==r,那么说明到了最底层
    {
        t[p].dat = t[p].ls = t[p].rs = t[p].sum = a[l];
        return;
    }
    /*左右递归*/
    int mid=(l+r)>>1;      //中间的数是,两者相加/2
    build(p<<1,l,mid);     //左面递归
    /* p*2是偶数,然后跟1按位或,就是+1的意思,总的意思是:p*2+1 */
    build(p<<1|1,mid+1,r); //右面递归
    update(p); //更新p点的值
}

void change(int p,int x,int v)
{
    if(t[p].l==t[p].r){
        t[p].dat=t[p].ls=t[p].rs=t[p].sum=v;
        return ;
    }
    int mid=(t[p].l+t[p].r)>>1;
    if(x<=mid) change(p<<1,x,v);
    else change(p<<1|1,x,v);
    update(p);
}

segment query(int p,int l,int r) //1 L~R区间的最大连续子段和 (从最开始的一号往下找)
{
    if(l<=t[p].l && r>=t[p].r) //如果L比p的l小,且R比p的r大,即:p所能确定的范围在l和r之间
    {
        return t[p]; //将p这个节点返回就好了
    }
    int mid = (t[p].l+t[p].r)>>1; //求出p点区间中心值
    segment nod,nod1,nod2;
    int f=0;
    if(l<=mid) //如果查询的l在中心值的左面
    {
        nod1=query(p<<1,l,r);
        f+=1;
    }
    if(r>mid) //如果查询的r在中心值的右面
    {
        nod2=query(p<<1|1,l,r);
        f+=2;
    }
    if(f==3) //那么两边一定都被遍历过
    {
        nod.sum = nod1.sum+nod2.sum; //如果l和r在mid的两遍,返回节点的sum值=两个节点区间之和
        nod.ls=max(nod1.ls,nod1.sum+nod2.ls);
        nod.rs=max(nod2.rs,nod2.sum+nod1.rs);
        nod.dat=max(nod1.dat,max(nod2.dat,nod1.rs+nod2.ls));
    }
    if(f==1) nod = nod1; //如果f==1,则表明只进行第一个if语句,
    if(f==2) nod = nod2;
    return nod;
}

int main()
{
    for (int i=1;i<=10;i++) //第二种输入方法
    {
        cin >> a[i];
    }
    int N,M;
    cin >> N >> M; //n是区间的大小,m次询问
    for(int i=1;i<=N;i++)
    {
        cin >> a[i];
    }
    build(1,1,N); // 1 1 N   当前节点编号,左面的,右面的
    int k,x,y;
    while(M--)
    {
        cin >> k >> x >> y;
        if(k==1) //查询
        {
            if(x>y) swap(x,y);   //将x和y从小到大排序
            cout << query(1,x,y).dat << endl; //dat是x,y中最大连续子段和
        }
        else change(1,x,y); //将a[x]变为y
    }
    return 0;
}