#include <bits/stdc++.h>
using namespace std;
struct Arbore
{
int st,dr,sol,lazy;
}Arb[400010];
///. st = cate libere ca prefix
///.dr = cate libere ca sufix
///.sol = cate libere ca secventa in cadrul intervalului din Arb
int N,Q,tip,l,r;
void init(int nod, int a, int b)
{
Arb[nod].st = Arb[nod].dr = Arb[nod].sol = b - a + 1;
if(a==b) return;
int mid=(a + b)/2;
init(nod*2, a, mid);
init(nod*2+1, mid+1, b);
}
void propag(int nod, int a, int b)
{
if(Arb[nod].lazy==0) return; /// nimic de propagat
if(Arb[nod].lazy==2) /// daca se elibereaza
Arb[nod].st = Arb[nod].dr = Arb[nod].sol = b - a + 1;
else
if(Arb[nod].lazy==1) /// daca se ocupa intervalul
Arb[nod].st = Arb[nod].dr = Arb[nod].sol = 0;
if(a<b) ///nu este frunza, deci exista fii atunci se propaga lazy catre ei
Arb[nod*2].lazy = Arb[nod*2+1].lazy = Arb[nod].lazy;
Arb[nod].lazy=0; /// se reseteaza lazy in nodul curent
}
void update(int nod, int a, int b, int ua, int ub,int val)
{
if(ua<=a && b<=ub)
{
Arb[nod].lazy = val;
propag(nod, a, b);
return;
}
propag(nod, a, b);
int mid = (a + b)/2;
if(ua <= mid) update(nod*2, a, mid, ua, ub, val);
else propag(nod*2, a, mid);
if(mid < ub) update(nod*2 + 1, mid + 1, b, ua, ub, val);
else propag(nod*2 + 1, mid + 1, b);
Arb[nod].sol=max(Arb[nod*2].dr + Arb[nod*2 + 1].st, max(Arb[nod*2].sol,Arb[nod*2+1].sol));
Arb[nod].st=Arb[nod*2].st;
if(Arb[nod].st == mid - a + 1) Arb[nod].st += Arb[nod*2 + 1].st;
Arb[nod].dr = Arb[nod*2 + 1].dr;
if(Arb[nod].dr == b - mid) Arb[nod].dr += Arb[nod*2].dr;
}
int main()
{
freopen("hotel.in","r",stdin);
freopen("hotel.out","w",stdout);
scanf("%d%d",&N, &Q);
init(1,1,N);
for(int i=1;i<=Q;i++)
{
scanf("%d",&tip);
if(tip==3) {
propag(1,1,N);
printf("%d\n",Arb[1].sol);
continue;
}
scanf("%d%d",&l,&r);
r += l-1;
update(1, 1, N, l, r, tip);
}
return 0;
}