#include <cstdio>
#include <algorithm>
#define SIZE 100000
using namespace std;
int n, m, op, pos, nr, A, B;
struct tree
{
int max_left; // nr max de camere libere consecutive care incep pe pozitia left
int max_right; // nr max de camere libere consecutive care se termina pe pozitia right
int MAX; // nr max de camere libere consecutive pe intervalul considerat
} int_tree[SIZE];
inline void build_tree(int, int, int);
inline void update(int, int, int, int);
inline int maxim( int a, int b )
{
if( a > b )
return a;
return b;
}
int main()
{
freopen("hotel.in", "r", stdin);
freopen("hotel.out", "w", stdout);
scanf("%d%d", &n, &m);
build_tree( 1, 1, n );
// int_tree[ 1 ].max_left = int_tree[ 1 ].max_right = int_tree[ 1 ].MAX = n;
while ( m-- )
{
scanf("%d", &op);
if( op != 3) // insert
{
scanf("%d%d", &pos, &nr); // pos pozitia de inceput, nr - numarul de camere care se vor ocupa
A = pos;
B = pos + nr - 1; // intervalul [A, B] => de la pos la nr se ocupa camerele
update(1, 1, n, op);
}
else // query
printf("%d\n", int_tree[ 1 ].MAX);
}
return 0;
}
inline void build_tree(int node, int left, int right)
{
if( left == right )
{
int_tree[ node ].max_left = int_tree[ node ].max_right = int_tree[ node ].MAX = 1;
return;
}
int middle = ( left + right ) / 2;
build_tree( 2 * node, left, middle );
build_tree( 2 * node + 1, middle + 1, right);
int_tree[ node ].MAX = int_tree[ node ].max_left = int_tree[ node ].max_right = right - left + 1;
}
inline void fill_rooms( int node )
{
int_tree[ node ].max_left = int_tree[ node ].max_right = int_tree[ node ].MAX = 0;
}
inline void empty_rooms( int node, int left, int right )
{
int_tree[ node ].MAX = int_tree[ node ].max_left = int_tree[ node ].max_right = right - left + 1;
}
inline void update(int node, int left, int right, int type)
{
if( A <= left && right <= B)
{
if( type == 1 )
fill_rooms( node );
else
empty_rooms( node, left, right );
// printf("!!!%d\n", node);
return ;
}
int middle = ( right + left ) / 2;
if( int_tree[ node ].MAX == right - left + 1) // toate camerele din intervalul reprezentat de node sunt goale
{
empty_rooms( 2 * node, left, middle); // => si cele din intervalele incluse in intervalul lui node trebuie sa fie goale
empty_rooms( 2 * node + 1, middle + 1, right);
}
if( int_tree[ node ].MAX == 0) // camerele din intervalul reprezentat de node sunt pline
{
fill_rooms( 2 * node ); // => si cele din fiii nodului node trebuie sa fie pline
fill_rooms( 2 * node + 1);
}
if( A <= middle )
update( 2 * node, left, middle, type);
if( B > middle )
update( 2 * node + 1, middle + 1, right, type);
int_tree[ node ].max_left = int_tree[ 2 * node ].max_left;
if( int_tree[ 2 * node ].max_left == middle - left + 1)
int_tree[ node ].max_left += int_tree[ 2 * node + 1 ].max_left;
int_tree[ node ].max_right = int_tree[ 2 * node + 1 ].max_right;
if( int_tree[ 2 * node + 1 ].max_right == right - middle)
int_tree[ node ].max_right += int_tree[ 2 * node ].max_right;
int_tree[ node ].MAX = maxim( maxim(int_tree[2 * node].MAX, int_tree[ 2 * node + 1].MAX),
int_tree[2 * node].max_right + int_tree[ 2 * node + 1].max_left);
}