#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <string>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <fstream>
#include <iterator>
#include <assert.h>
using namespace std;
const string file = "hotel";
const string infile = file + ".in";
const string outfile = file + ".out";
const int INF = 0x3f3f3f3f;
struct NodeInfo
{
NodeInfo(int ans = 1, int left = 1, int right = 1, int length = 1, bool lazy = true)
{
this->ans = ans;
this->left = left;
this->right = right;
this->length = length;
this->lazy = lazy;
}
int ans;
int left;
int right;
int length;
bool lazy;
};
class SegmentTree
{
public:
SegmentTree(int st, int dr);
int query(int a, int b);
void update(int a, int b, int free);
private:
void updateNode(NodeInfo& info, NodeInfo& l, NodeInfo& r);
void query(int nod, int st, int dr, int a, int b, NodeInfo& info);
void update(int nod, int st, int dr, int a, int b, int value);
void forceUpdate(int nod, int st, int dr, int a, int b, int value);
int _st;
int _dr;
vector<NodeInfo> _data;
};
void SegmentTree::updateNode(NodeInfo& info, NodeInfo& l, NodeInfo& r)
{
info.ans = max(l.ans, r.ans);
info.ans = max(info.ans, l.right + r.left);
info.left = l.left;
info.right = r.right;
info.length = l.length + r.length;
if(l.left == l.length)
{
info.left = l.left + r.left;
}
if(r.right == r.length)
{
info.right = l.right + r.right;
}
}
SegmentTree::SegmentTree(int st, int dr)
{
_st = st;
_dr = dr;
int size = dr - st + 1;
int c = 1;
while( c < size)
c <<= 1;
c <<= 1;
c++;
_data.resize(c);
}
void SegmentTree::query(int nod, int st, int dr, int a, int b, NodeInfo& info)
{
if(_data[nod].lazy == true)
{
forceUpdate(nod, st, dr, st ,dr, _data[nod].ans);
}
if(a <= st && dr <= b)
{
info = _data[nod];
return;
}
int mid = (dr + st)/2;
NodeInfo l;
NodeInfo r;
if(a <= mid && mid < b)
{
query(nod*2, st, mid, a, b, l);
query(nod*2 + 1, mid + 1, dr, a, b, r);
updateNode(info, l, r);
}
else if(a <= mid)
{
query(nod*2, st, mid, a, b, l);
info = l;
}
else if( mid < b)
{
query(nod*2 + 1, mid + 1, dr, a, b, r);
info = r;
}
}
void SegmentTree::update(int nod, int st, int dr, int a, int b, int value)
{
if(a <= st && dr <= b)
{
if(value == 1)
{
_data[nod] = NodeInfo(dr - st + 1, dr - st + 1, dr - st + 1, dr - st + 1);
}
else
{
_data[nod] = NodeInfo(0, 0, 0, dr - st + 1);
}
if(st == dr)
{
_data[nod].lazy = false;
}
return;
}
if(_data[nod].lazy == true)
{
forceUpdate(nod, st, dr, st, dr, _data[nod].ans);
}
int mid = (dr + st)/2;
if(a <= mid)
{
update(nod*2, st, mid, a, b, value);
}
if( mid < b)
{
update(nod*2 + 1, mid + 1, dr, a, b, value);
}
updateNode(_data[nod], _data[nod*2], _data[nod*2+1]);
}
void SegmentTree::forceUpdate(int nod, int st, int dr, int a, int b, int value)
{
if(value == 1)
{
_data[nod] = NodeInfo(dr - st + 1, dr - st + 1, dr - st + 1, dr - st + 1);
}
else
{
_data[nod] = NodeInfo(0, 0, 0, dr - st + 1);
}
_data[nod].lazy = false;
if(st == dr)
return;
int mid = (dr + st)/2;
forceUpdate(nod*2, st, mid, a, b, value);
forceUpdate(nod*2 + 1, mid + 1, dr, a, b, value);
}
void SegmentTree::update(int a, int b, int free)
{
update(1, _st, _dr, a, b, free);
}
int SegmentTree::query(int a, int b)
{
NodeInfo info;
query(1, _st, _dr, a, b, info);
return info.ans;
}
int main()
{
#ifdef ONLINE_JUDGE
ostream &fout = cout;
istream &fin = cin;
#else
fstream fout(outfile.c_str(), ios::out);
fstream fin(infile.c_str(), ios::in);
#endif
int N, P;
fin >> N >> P;
SegmentTree tree(1, N);
for(int i = 0; i < P; i++)
{
int op;
int x, y;
fin >> op;
if(op == 1)
{
fin >> x >> y;
tree.update(x, x + y - 1, 0);
}
else if(op == 2)
{
fin >> x >> y;
tree.update(x, x + y - 1, 1);
}
else if(op == 3)
{
fout << tree.query(1, N) << "\n";
}
}
#ifdef ONLINE_JUDGE
#else
fin.close();
fout.close();
#endif
}