#include <iostream>
#include <fstream>
using namespace std;
ifstream fin("hotel.in");
ofstream fout("hotel.out");
int n,m,p,c,i,j,a,b;
struct nod
{ int lst,ldr,lmx,spart; } ar[400005];
void calc (int nd,int st,int dr)
{
int md=(st+dr)/2;
ar[nd].lmx=max(ar[2*nd].lmx,max(ar[2*nd+1].lmx,ar[2*nd].ldr+ar[2*nd+1].lst));
ar[nd].lst=(ar[2*nd].lst==md-st+1)?(ar[2*nd].lst+ar[2*nd+1].lst):ar[2*nd].lst;
ar[nd].ldr=(ar[2*nd+1].ldr==dr-md)?(ar[2*nd+1].ldr+ar[2*nd].ldr):ar[2*nd+1].ldr;
} //asta calculeaza lungimea maxima pentru un nod din fii sai
void spart (int nd,int st,int dr)
{
ar[nd].lmx=ar[nd].lst=ar[nd].ldr=0;
ar[nd].spart=1;
return;
}//asta imi seteaza un interval ca fiind spart.
void initial (int nd,int st,int dr)
{
ar[nd].spart=0;
if(st==dr)
{
ar[nd].lst=ar[nd].ldr=ar[nd].lmx=1;
return;
}
int md=(st+dr)/2;
initial(2*nd,st,md);
initial(2*nd+1,md+1,dr);
calc(nd,st,dr);
}//cu asta mi-am construit valorile initiale.
void block (int nd,int st,int dr)
{
if(a<=st&&dr<=b)
{
spart(nd,st,dr);
return;
}
int md=(st+dr)/2;
if(max(a,st)<=min(b,md)) block(2*nd,st,md);
if(max(a,md+1)<=min(b,dr)) block(2*nd+1,md+1,dr);
calc(nd,st,dr);
}//cu asta fac intervalul dat "spart" si recalculez cu valoare nodurilor fiind 0.
void open (int nd,int st,int dr,bool ok)
{
if(st==dr)
{
ar[nd].lst=ar[nd].ldr=ar[nd].lmx=1;
ar[nd].spart=0;
return;
}
if(ar[nd].spart==1)
{
ok=1;
ar[nd].spart=0;
}
int md=(st+dr)/2;
if(max(a,st)<=min(b,md)) open(2*nd,st,md,ok);
else if(ok) spart(2*nd,st,dr);
if(max(a,md+1)<=min(b,dr)) open(2*nd+1,md+1,dr,ok);
else if(ok) spart(2*nd+1,md+1,dr);
calc(nd,st,dr);
}
int main() {
//bun deci care ii schema?
//imi fac o fuctie care blocheaza cateva intervale dandu-le costul 0 apoi calculeaza raspunsul.
//intervalele blocate le numesc sparte :))
//a doua functie sparge intervalele si noteaza ca sparte toate subintervalele inafara de cel selectat.
initial(1,1,12);
fin>>n>>p;
while(p--)
{
fin>>c;
if(c==3) fout<<ar[1].lmx<<"\n";
if(c==1)
{
fin>>a>>b;
b=a+b-1;
block(1,1,n);
}
if(c==2)
{
fin>>a>>b;
b=a+b-1;
open(1,1,n,0);
}
}
}