#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cctype>
#define _for(i,a,b) for(int i=(a);i<(b);++i)
#define _rep(i,a,b) for(int i=(a);i<=(b);++i)
using namespace std;
typedef long long LL;
inline int read_int(){
int t=0;bool sign=false;char c=getchar();
while(!isdigit(c)){sign|=c=='-';c=getchar();}
while(isdigit(c)){t=(t<<1)+(t<<3)+(c&15);c=getchar();}
return sign?-t:t;
}
inline void write(LL x){
register char c[21],len=0;
if(!x)return putchar('0'),void();
if(x<0)x=-x,putchar('-');
while(x)c[++len]=x%10,x/=10;
while(len)putchar(c[len--]+48);
}
inline void space(LL x){write(x),putchar(' ');}
inline void enter(LL x){write(x),putchar('\n');}
const int MAXN=1e5+5,inf=1e9;
const double alpha=0.75;
struct Point{
int x,y;
Point(int x=0,int y=0):x(x),y(y){}
bool in(int x1,int y1,int x2,int y2){return x1<=x&&x<=x2&&y1<=y&&y<=y2;}
void get_min(const Point &a,const Point &b){
x=min(x,min(a.x,b.x));
y=min(y,min(a.y,b.y));
}
void get_max(const Point &a,const Point &b){
x=max(x,max(a.x,b.x));
y=max(y,max(a.y,b.y));
}
};
struct Node{
int ch[2],cnt;
Point p,r1,r2;
void build(Point P){
p=r1=r2=P;
ch[0]=ch[1]=0;
cnt=1;
}
bool in(int x1,int y1,int x2,int y2){return x1<=r1.x&&y1<=r1.y&&x2>=r2.x&&y2>=r2.y;}
bool out(int x1,int y1,int x2,int y2){return x2<r1.x||y2<r1.y||x1>r2.x||y1>r2.y;}
}node[MAXN];
bool isbad(int pos){return alpha*node[pos].cnt<max(node[node[pos].ch[0]].cnt,node[node[pos].ch[1]].cnt)?true:false;}
void maintain(int pos){
node[pos].r1.get_min(node[node[pos].ch[0]].r1,node[node[pos].ch[1]].r1);
node[pos].r2.get_max(node[node[pos].ch[0]].r2,node[node[pos].ch[1]].r2);
node[pos].cnt=node[node[pos].ch[0]].cnt+node[node[pos].ch[1]].cnt+1;
}
int pool[MAXN],pos1,pos2,root,dimension;
Point temp[MAXN];
bool cmp(const Point &p1,const Point &p2){
if(!dimension)return p1.x<p2.x||(p1.x==p2.x&&p1.y<p2.y);
return p1.y<p2.y||(p1.y==p2.y&&p1.x<p2.x);
}
void Init(int n){
node[0].r1=Point(inf,inf);
node[0].r2=Point(-inf,-inf);
for(int i=n;i>=1;i--)
pool[++pos1]=i;
}
void build(int &pos,int lef,int rig,bool d){
if(lef>rig) return pos=0,void();
pos=pool[pos1--];
int mid=lef+rig>>1;
dimension=d;
nth_element(temp+lef,temp+mid,temp+rig+1,cmp);
node[pos].p=node[pos].r1=node[pos].r2=temp[mid];
build(node[pos].ch[0],lef,mid-1,!d);
build(node[pos].ch[1],mid+1,rig,!d);
maintain(pos);
}
void build(int n){build(root,1,n,false);}
void dfs(int pos){
if(!pos)return;
dfs(node[pos].ch[0]);
pool[++pos1]=pos,temp[++pos2]=node[pos].p;
dfs(node[pos].ch[1]);
}
void rebuild(int &pos,bool d){
pos2=0;
dfs(pos);
build(pos,1,pos2,d);
}
void check(int &pos,Point x,bool d){
if(pos){
if(isbad(pos)){
rebuild(pos,d);
return;
}
dimension=d;
if(cmp(node[pos].p,x))
check(node[pos].ch[1],x,!d);
else
check(node[pos].ch[0],x,!d);
}
}
void Insert(int &pos,Point x,bool d){
if(!pos){
pos=pool[pos1--];
node[pos].build(x);
return;
}
node[pos].cnt++;
dimension=d;
if(cmp(node[pos].p,x))Insert(node[pos].ch[1],x,!d);
else Insert(node[pos].ch[0],x,!d);
maintain(pos);
}
void Insert(Point x){
Insert(root,x,false);
check(root,x,false);
}
int query(int pos,int x1,int y1,int x2,int y2){
if(!pos)
return 0;
if(node[pos].in(x1,y1,x2,y2))
return node[pos].cnt;
else if(node[pos].out(x1,y1,x2,y2))
return 0;
return query(node[pos].ch[0],x1,y1,x2,y2)+query(node[pos].ch[1],x1,y1,x2,y2)+node[pos].p.in(x1,y1,x2,y2);
}
int query(int x1,int y1,int x2,int y2){
return query(root,x1,y1,x2,y2);
}
int main()
{
int n=read_int(),m=read_int(),opt,x,y;
Init(MAXN-1);
while(m--){
opt=read_int(),x=read_int(),y=read_int();
if(opt==1)
Insert(Point(x,y));
else
enter(query(1,y,x,n));
}
return 0;
}