//Problema se rezolva in O(p*logn) cu Lazy Update pe Arbori de Intervale
#include <fstream>
using namespace std;
//Un nod al arborelui de intervale
struct nod
{
int st,dr;
int pref,suf,best;
//bool lenes;
//int val_lenes;
nod()
{
st=0;
dr=0;
pref=0;
suf=0;
best=0;
// lenes=0;
// val_lenes=0;
}
}arb[262144]; //Arborele de intervale este retinut in memorie sub forma de heap
//Aceasta functie construieste arborele
void build(int st,int dr,int poz)
{
arb[poz].st=st;
arb[poz].dr=dr;
arb[poz].suf=arb[poz].pref=arb[poz].best=(dr-st+1);
//arb[poz].lenes=0;
//arb[poz].val_lenes=0;
if(st<dr)
{
int mijl=(st+dr)>>1;
build(st,mijl,poz<<1);
build(mijl+1,dr,(poz<<1)+1);
}
}
//Functie de maxim
inline int maxim(int a,int b)
{
if(a>b)
return a;
return b;
}
//Functie de maxim (cu trei numere)
inline int maxim(int a,int b,int c)
{
return maxim(maxim(a,b),c);
}
//Recalculeaza informatiile dintr-un nod in functie de cele din fii sai deja calculati
inline void recompute(nod &a,nod b,nod c)
{
if((b.dr-b.st+1)==b.pref)
a.pref=b.pref+c.pref;
else
a.pref=b.pref;
if((c.dr-c.st+1)==c.suf)
a.suf=c.suf+b.suf;
else
a.suf=c.suf; //GRESEALA: scrisesem a.pref in loc de a.suf!!!!!!
a.best=maxim(b.best,c.best,b.suf+c.pref);
}
//Face lenesi cu valoarea val fii nodului arb[poz]
inline void fii_lenesi(int poz,int val)
{
arb[poz<<1].suf=arb[poz<<1].pref=arb[poz<<1].best=val*(arb[poz<<1].dr-arb[poz<<1].st+1);
arb[(poz<<1)+1].suf=arb[(poz<<1)+1].pref=arb[(poz<<1)+1].best=val*(arb[(poz<<1)+1].dr-arb[(poz<<1)+1].st+1);
}
//Pune valoarea 1 pe un interval
void update_0(int st,int dr,int poz)
{
//Daca intervalul curent este total exclus din arb[poz]
if((arb[poz].dr<st) || (arb[poz].st>dr))
return;
//Daca arb[poz] este un singur element ce apartine intervalui
if(arb[poz].st==arb[poz].dr && arb[poz].st==st)
{
arb[poz].pref=arb[poz].suf=arb[poz].best=1;
return;
}
//Daca intervalul e gol
if(arb[poz].best==0)
fii_lenesi(poz,0);
else if(arb[poz].best==(arb[poz].dr-arb[poz].st+1)) //Daca intervalul e plin
fii_lenesi(poz,1);
if(arb[poz].st==st && arb[poz].dr==dr) //Daca am "nimerit" intervalul
{
arb[poz].pref=arb[poz].suf=arb[poz].best=(arb[poz].dr-arb[poz].st+1);
return;
}
//Impartim in 2 intervalul
int mijl=(arb[poz].st+arb[poz].dr)>>1;
if(dr<=mijl)
update_0(st,dr,poz<<1);
else if(st>mijl)
update_0(st,dr,(poz<<1)+1);
else
update_0(st,mijl,poz<<1),update_0(mijl+1,dr,(poz<<1)+1);
recompute(arb[poz],arb[poz<<1],arb[(poz<<1)+1]);
}
//Idem cu update_0
void update_1(int st,int dr,int poz)
{
if((arb[poz].dr<st) || (arb[poz].st>dr))
return;
if(arb[poz].st==arb[poz].dr && arb[poz].st==st)
{
arb[poz].pref=arb[poz].suf=arb[poz].best=0;
return;
}
if(arb[poz].best==0)
fii_lenesi(poz,0);
else if(arb[poz].best==(arb[poz].dr-arb[poz].st+1))
fii_lenesi(poz,1);
if(arb[poz].st==st && arb[poz].dr==dr)
{
arb[poz].pref=arb[poz].suf=arb[poz].best=0;
return;
}
int mijl=(arb[poz].st+arb[poz].dr)>>1;
if(dr<=mijl)
update_1(st,dr,poz<<1);
else if(st>mijl)
update_1(st,dr,(poz<<1)+1);
else
update_1(st,mijl,poz<<1),update_1(mijl+1,dr,(poz<<1)+1);
recompute(arb[poz],arb[poz<<1],arb[(poz<<1)+1]);
}
int main()
{
ifstream cin("hotel.in");
ofstream cout("hotel.out");
int n,p,cod,i,a,b;
//Citim marimea intervalului arb[1] respectiv numarul de intrebari
cin>>n>>p;
build(1,n,1);
//Citim si solutionam intrebarile
for(i=0;i<p;i++)
{
cin>>cod;
if(cod<3)
{
cin>>a>>b;
b=(a+b-1);
}
if(cod==1)
update_1(a,b,1);
else if(cod==2)
update_0(a,b,1);
else
cout<<arb[1].best<<'\n';
}
cin.close();
cout.close();
//system("PAUSE");
return 0;
}