/*少说话,多做事*/
#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;
}