/*
1.若N比较小,则可以用二维的树状数组或线段树来做,但是500000,空间开不下,于是考虑离线CDQ。
子矩阵的数字和表示为也就是二维前缀和,因此一个要查询的子矩阵,
对其有影响的矩阵为s[x2][y2],s[x2][y1-1],s[x1-1][y2],s[x1-1][y1-1]这四个前缀子矩阵
所以,在没有修改操作的时候,这是一个二维偏序了裸题
但当加入了操作顺序这个玩意的时候,就是一个三维偏序。
其实对于操作顺序的处理也就是 CDQ 分治的过程,而每次分治,处理的都仅限于左边的修改对右边查询的影响。
为了判断是查询和修改,我用了一个 opt 变量。
2.注意这个tim的妙用
通过和 vis[] 数组结合,让不属于当前递归的BIT中的贡献被忽略
具体的忽略方式主要是在 ask() 里面
为了和 ask() 配合, add() 函数做出改变,通过另一种方式清空并修改。
3.有一个妙点是对于 opt 的利用,通过这个,处理了将操作和询问一同放入 p[] 的分辨问题
可以直接通过 while 盘掉,注意 while 边界。
4.啊啊啊啊啊啊啊,易错点,
不要把 sort(p+l,p+mid+1) 写成 sort(p+1,p+mid+1)
调了我一个小时多。。。(彩笔一个)
5.双倍经验:[BZOJ1176]Mokia
*/
#include<bits/stdc++.h>
using namespace std;
const int N = 800005;
const int M = 2000005;
int n,totp,totq,tim;
int opt,x,y,xx,yy,val;
int vis[M],ans[N],pos[N];
struct Point{
int x,y,ord,opt,val;
bool operator <(const Point &b)const{
return x==b.x?ord<b.ord:x<b.x;
}
}p[M];
struct BIT{
int c[M];
int lowbit(int x){return -x&x;}
void add(int x,int val){
for(;x<=n;x+=lowbit(x)){
if(vis[x]!=tim)vis[x]=tim,c[x]=val;
else c[x]+=val;
}
}
int ask(int x){
int res=0;
for(;x;x-=lowbit(x))
if(vis[x]==tim)res+=c[x];
return res;
}
}bit;
void solve(int l,int r){
if(l==r)return ;
int mid=(l+r)>>1;
solve(l,mid);solve(mid+1,r);
sort(p+l,p+mid+1);sort(p+mid+1,p+r+1);
tim++;
int p1=l,p2=mid+1;
while(p2<=r){
while(p1<=mid&&p[p1].opt==2)p1++;
while(p2<=r&&p[p2].opt==1)p2++;
if(p1<=mid&&p[p1].x<=p[p2].x)bit.add(p[p1].y,p[p1].val),p1++;
else if(p2<=r)ans[p[p2].ord]+=bit.ask(p[p2].y),p2++;
}
}
int main(){
scanf("%d",&n);
while(1){
scanf("%d",&opt);
if(opt==3)break;
scanf("%d%d",&x,&y);
if(opt==1){
scanf("%d",&val);
p[++totp]={x,y,totp,opt,val};
}else{
scanf("%d%d",&xx,&yy);
pos[++totq]=totp;
p[++totp]={x-1,y-1,totp,opt,0};
p[++totp]={xx,y-1,totp,opt,0};
p[++totp]={x-1,yy,totp,opt,0};
p[++totp]={xx,yy,totp,opt,0};
}
}
solve(1,totp);
for(int i=1;i<=totq;i++)
printf("%d\n",ans[pos[i]+1]-ans[pos[i]+2]-ans[pos[i]+3]+ans[pos[i]+4]);
return 0;
}