/*
程序功能:线段树区间求和求最值,点更新。
time :2014/1/20
code by wdsaid
*/
#include<stdio.h>
#define M 100050//区间长度
#define INF 1e9 //无穷大
int val[M]; //保存节点权值
int sum,max,min;//保存最终结果
struct node //存储节点信息
{
int l,r;
int sum;
int max;
int min;
int mid(){return (l+r)>>1;}//取中点用于二分查找
}T[M*4];
int Max(int a,int b)
{
return a>b?a:b;
}
int Min(int a,int b)
{
return a<b?a:b;
}
void Build(int l,int r,int root)//建树
{
T[root].l=l;T[root].r=r;
if(l==r)
{
T[root].sum=val[l];
T[root].max=T[root].min=val[l];
return;
}
int mid=T[root].mid();
Build(l,mid,root<<1);
Build(mid+1,r,root<<1|1);
T[root].sum=T[root<<1].sum+T[root<<1|1].sum;
T[root].max=Max(T[root<<1].max,T[root<<1|1].max);
T[root].min=Min(T[root<<1].min,T[root<<1|1].min);
}
void Query(int l,int r,int root)//查询
{
if(T[root].l==l&&T[root].r==r)
{
sum+=T[root].sum;
max=Max(max,T[root].max);
min=Min(min,T[root].min);
return;
}
int mid=T[root].mid();
if(r<=mid) Query(l,r,root<<1);
else if(l>mid)Query(l,r,root<<1|1);
else
{
Query(l,mid,root<<1);
Query(mid+1,r,root<<1|1);
}
}
void Modify(int root,int a,int d)//点更改
{
if(a==T[root].l && a==T[root].r)
{
T[root].sum=T[root].max=T[root].min=d;
return;
}
int mid=T[root].mid();
if(a<=mid) Modify(root<<1,a,d);
else Modify(root<<1|1,a,d);
T[root].sum=T[root<<1].sum+T[root<<1|1].sum;
T[root].max=Max(T[root<<1].max,T[root<<1|1].max);
T[root].min=Min(T[root<<1].min,T[root<<1|1].min);
}
int main()
{
int m,n,i,p,x,y;
scanf("%d %d",&n,&m);
for(i=1;i<=n;i++) scanf("%d",&val[i]);
Build(1,n,1);
for(i=1;i<=m;i++)
{
max=-INF,min=INF,sum=0;
scanf("%d %d %d",&p,&x,&y);
switch(p)
{
case 1:Modify(1,x,y);break;
case 2:Query(x,y,1);printf("%d\n",sum);break;
case 3:Query(x,y,1);printf("%d\n",max);break;
default:break;
}
}
}