package 洛谷;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
public class P3372模板線段樹1
{
static final int MAX_SIZE=1000001;
static int tree[]=new int[MAX_SIZE<<2];//n*4必定不過界
static int lazyTag[]=new int[MAX_SIZE<<2];//懶惰標記
static int a[]=new int[MAX_SIZE];//需要構建線段樹的數組
static int N,M;//N當前數據量 M操作數個數
public static void main(String[] args) throws IOException
{
BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(System.in));
String[]strings=bufferedReader.readLine().trim().split(" ");
N=Integer.parseInt(strings[0]);M=Integer.parseInt(strings[1]);
// tree=new int[N<<2];lazyTag=new int[N<<2];a=new int[N];
strings=bufferedReader.readLine().trim().split(" ");
for (int i = 0; i < strings.length; i++)
{
a[i+1]=Integer.parseInt(strings[i]);
}
build(1, 1, N);
for (int i = 0; i < M; i++)
{
strings=bufferedReader.readLine().trim().split(" ");
int opr=Integer.parseInt(strings[0]);
if (opr==1)
{
int x=Integer.parseInt(strings[1]);
int y=Integer.parseInt(strings[2]);
int k=Integer.parseInt(strings[3]);
update(x, y, 1, 1, N, k);
}
else
{
int x=Integer.parseInt(strings[1]);
int y=Integer.parseInt(strings[2]);
System.out.println(query(x, y, 1, N, 1));
}
}
}
/**
* 左孩子的索引
* @param p 當前節點
* @return
*/
public static int leftChild(int p)
{
return p<<1;//p*2
}
/**
* 右孩子的索引
* @param p 當前節點
* @return
*/
public static int rightChild(int p)
{
return (p<<1)|1;//p*2+1
}
/**
* 先去整合子節點的信息,再向它們的祖先回溯整合之後的信息
* 向上傳導信息
* @param p 當前節點
*/
public static void pushUp(int p)
{
tree[p]=tree[leftChild(p)]+tree[rightChild(p)];
}
/**
* 建樹
* @param p 當前節點
* @param l 左邊界
* @param r 右邊界
*/
public static void build(int p,int l,int r)
{
lazyTag[p]=0;
//如果左右區間相同,那麼必然是葉子節點啦,只有葉子節點是被真實賦值的
if (l==r)
{
tree[p]=a[l];
return;
}
int mid=(l+r)>>1;// /2
build(leftChild(p), l, mid);
build(rightChild(p), mid+1, r);
pushUp(p);
}
/**
* 區間更新
* 單點修改就是區間更新的特例
* @param needL 需要修改的左邊界
* @param needR 需要修改的右邊界
* @param p 當前節點
* @param l 當前節點所存儲的區間的左邊界
* @param r 當前節點所存儲的區間的右邊界
* @param k 修改的值
*/
public static void update(int needL,int needR,int p,int l,int r,int k)
{
if (needL<=l&&r<=needR)
{
tree[p]+=k*(r-l+1);
lazyTag[p]+=k;
return;
}
pushDown(p,l,r);
int mid=(l+r)>>1;// /2
if (needL<=mid)
{
update(needL, needR, leftChild(p), l, mid, k);
}
if (needR>mid)
{
update(needL, needR, rightChild(p), mid+1, r, k);
}
//更新完子節點後更新自己
pushUp(p);
}
/**
* 向下更新
* @param p 當前節點
* @param l 左邊界
* @param r 右邊界
*/
public static void pushDown(int p, int l, int r)
{
int mid=(l+r)>>1;// /2
//每次更新兩個兒子節點
f(leftChild(p),l,mid,lazyTag[p]);
f(rightChild(p),mid+1,r,lazyTag[p]);
lazyTag[p]=0;//本節點不再lazy了
}
/**
* 記錄當前節點所代表的區間
* @param p 當前節點
* @param l 左邊界
* @param r 右邊界
* @param k 要更新的值
*/
public static void f(int p, int l, int r, int k)
{
lazyTag[p]=lazyTag[p]+k;
tree[p]=tree[p]+k*(r-l+1);//由於是這個區間統一改變故改變多少,就增加多少
}
/**
* 區間查詢
* @param queryX 查詢左邊界
* @param queryY 查詢右邊界
* @param l 左邊界
* @param r 右邊界
* @param p 當前節點
*/
public static int query(int queryX, int queryY, int l, int r, int p)
{
int result=0;
if (queryX<=l&&r<=queryY)
{
return tree[p];
}
int mid=(l+r)>>1;// /2
pushDown(p, l, r);
if (queryX<=mid)
{
result+=query(queryX, queryY, l, mid, leftChild(p));
}
if (queryY>mid)
{
result+=query(queryX, queryY, mid+1, r, rightChild(p));
}
return result;
}
}