#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N_MAX = 1e5 + 1, INF = INT_MAX;
int N, M;
void SetInput(string name)
{
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
freopen((name + ".in").c_str(), "r", stdin);
freopen((name + ".out").c_str(), "w", stdout);
}
struct LazySegmentTree
{
struct Node
{
int maxi; // the length of the longest subarray of 0
int leftMaxi, rightMaxi;
int len;
void SetAllValues(int value)
{
maxi = leftMaxi = rightMaxi = value;
}
bool flagged; // means that this node's children are not updated
};
Node A[4 * N_MAX];
int bg, ed, value; // local variables for Update and Query
inline int Maxi(int a, int b)
{
return a > b ? a : b;
}
Node MaxiR(Node& a, Node& b) // Maxi with both Nodes as references
{
Node temp;
temp.leftMaxi = a.leftMaxi;
if(a.leftMaxi == a.len)
temp.leftMaxi = b.leftMaxi + a.len;
temp.rightMaxi = b.rightMaxi;
if(b.rightMaxi == b.len)
temp.rightMaxi = a.rightMaxi + b.len;
temp.maxi = max({temp.leftMaxi, temp.rightMaxi, a.rightMaxi + b.leftMaxi, a.maxi, b.maxi});
temp.len = a.len + b.len;
temp.flagged = false;
return temp;
}
Node Maxi(Node& a, Node b) // Maxi with one Node as references
{
Node temp;
temp.leftMaxi = a.leftMaxi;
if(a.leftMaxi == a.len)
temp.leftMaxi = b.leftMaxi + a.len;
temp.rightMaxi = b.rightMaxi;
if(b.rightMaxi == b.len)
temp.rightMaxi = a.rightMaxi + b.len;
temp.maxi = max({temp.leftMaxi, temp.rightMaxi, a.rightMaxi + b.leftMaxi, a.maxi, b.maxi});
temp.len = a.len + b.len;
temp.flagged = false;
return temp;
}
void Build(int node, int L, int R)
{
if(L == R)
{
// cin >> A[node].value;
/// We set all base nodes to 0, so the max is the node's length
A[node].SetAllValues(1);
A[node].len = 1;
A[node].flagged = false;
return;
}
int m = (L + R) >> 1;
Build(node << 1, L, m);
Build((node << 1) + 1, m + 1, R);
A[node] = MaxiR(A[node << 1], A[(node << 1) + 1]);
A[node].len = R - L + 1;
}
void Update(int bg, int ed, int value) // Value can be 0 or 1
{
this->bg = bg;
this->ed = ed;
this->value = value;
_Update(1, 1, N);
}
void _Update(int node, int L, int R)
{
if(bg <= L && R <= ed)
{
if(value == 0)
A[node].SetAllValues(R - L + 1);
else
A[node].SetAllValues(0);
A[node].flagged = true;
return;
}
if(A[node].flagged)
{
if(A[node].maxi == 0)
{
A[node << 1].SetAllValues(0);
A[(node << 1) + 1].SetAllValues(0);
}else
{
A[node << 1].SetAllValues(A[node << 1].len);
A[(node << 1) + 1].SetAllValues(A[(node << 1) + 1].len);
}
A[node << 1].flagged = A[(node << 1) + 1].flagged = true;
A[node].flagged = false;
}
int m = (L + R) >> 1;
if(bg <= m)
_Update(node << 1, L, m);
if(m < ed)
_Update((node << 1) + 1, m + 1, R);
A[node] = MaxiR(A[node << 1], A[(node << 1) + 1]);
}
int Query(int bg, int ed)
{
this->bg = bg;
this->ed = ed;
return Query(1, 1, N);
}
int Query(int node, int L, int R)
{
if(bg <= L && R <= ed)
return A[node].maxi;
if(A[node].flagged)
{
if(A[node].maxi == 0)
{
A[node << 1].SetAllValues(0);
A[(node << 1) + 1].SetAllValues(0);
}else
{
A[node << 1].SetAllValues(A[node << 1].len);
A[(node << 1) + 1].SetAllValues(A[(node << 1) + 1].len);
}
A[node << 1].flagged = A[(node << 1) + 1].flagged = true;
A[node].flagged = false;
}
int m = (L + R) >> 1;
int temp = -INF;
if(bg <= m)
temp = Maxi(temp, Query(node << 1, L, m));
if(m < ed)
temp = Maxi(temp, Query((node << 1) + 1, m + 1, R));
return temp;
}
} tree;
int main()
{
SetInput("hotel");
cin >> N >> M;
tree.Build(1, 1, N);
int t, a, b;
while(M--)
{
cin >> t;
switch(t)
{
case 1:
cin >> a >> b;
tree.Update(a, a + b - 1, 1);
break;
case 2:
cin >> a >> b;
tree.Update(a, a + b - 1, 0);
break;
case 3:
cout << tree.A[1].maxi << '\n';
}
}
return 0;
}