#include <iostream>
#include <fstream>
using namespace std;
ifstream in("hotel.in");
ofstream out("hotel.out");
int const nmax = 100000;
struct Node {
int sol;
int le;
int ri;
bool empty;
bool full;
};
Node initempty(int from, int to) {
Node ans;
ans.sol = to - from + 1;
ans.le = to - from + 1;
ans.ri = to - from + 1;
ans.empty = true;
ans.full = false;
return ans;
}
Node initfull() {
Node ans;
ans.sol = 0;
ans.le = 0;
ans.ri = 0;
ans.empty = false;
ans.full = true;
return ans;
}
int n, p;
Node aint[1 + 4 * nmax];
Node merge(Node a, Node b) {
Node ans;
ans.sol = max(max(a.sol, b.sol), a.ri + b.le);
if (a.empty)
ans.le = a.le + b.le;
else
ans.le = a.le;
if (b.empty)
ans.ri = a.ri + b.ri;
else
ans.ri = b.ri;
if (a.empty && b.empty)
ans.empty = true;
else
ans.empty = false;
if (a.full && b.full)
ans.full = true;
else
ans.full = false;
return ans;
}
void buildtree(int node, int from, int to) {
if (from == to) {
aint[node] = {1, 1, 1, 1, 0};//initempty(from, to);
} else {
int mid = (from + to) / 2;
buildtree(2 * node, from, mid);
buildtree(2 * node + 1, mid + 1, to);
aint[node] = merge(aint[2 * node], aint[2 * node + 1]);
}
}
void update(int node, int from, int to, int x, int y, bool fill) {
if (from == to) {
if (fill == true)
aint[node] = {0, 0, 0, 0, 1};
else
aint[node] = {1, 1, 1, 1, 0};
} else {
int mid = (from + to) / 2;
if (x <= mid)
update(2 * node, from, mid, x, min(y, mid), fill);
if (mid + 1 <= y)
update(2 * node + 1, mid + 1, to, max(x, mid + 1), y, fill);
aint[node] = merge(aint[2 * node], aint[2 * node + 1]);
}
}
int main() {
in >> n >> p;
buildtree(1, 1, n);
for (int i = 1; i <= p; i++) {
int query;
in >> query;
if (query == 1 || query == 2) {
int from, to;
in >> from >> to;
to = from + to - 1;
int fill = 2 - query; //1 means fill, 2 means empty
update(1, 1, n, from, to, fill);
} else
out << aint[1].sol << '\n';
}
return 0;
}