#include <bits/stdc++.h>
using namespace std;
int N, Q;
int C, A;
vector<int> App[300005];
int Updated[300005];
int Tree[1200055];
int NextPos = 0;
int MaxRead = 0;
int Query(int QL, int QR, int L, int R, int P) {
  if (QL <= L && R <= QR) return Tree[P];
  if (R < QL || QR < L) return 0;
  int Mid = (L + R) >> 1;
  return (Query(QL, QR, L, Mid, ((P << 1) + 1)) +
          Query(QL, QR, Mid + 1, R, ((P << 1) + 2)));
}
void Update(int idx, int Val, int L, int R, int P) {
  if (L == R) {
    Tree[P] = Val;
    return;
  }
  int Mid = (L + R) >> 1;
  if (idx <= Mid)
    Update(idx, Val, L, Mid, ((P << 1) + 1));
  else
    Update(idx, Val, Mid + 1, R, ((P << 1) + 2));
  Tree[P] = Tree[((P << 1) + 1)] + Tree[((P << 1) + 2)];
}
int main() {
  scanf("%d%d", &N, &Q);
  for (int i = 0; i < Q; i++) {
    scanf("%d%d", &C, &A);
    if (C == 1) {
      Update(NextPos, 1, 0, Q - 1, 0);
      App[A].push_back(NextPos++);
    } else if (C == 2) {
      int i =
          lower_bound(App[A].begin(), App[A].end(), max(MaxRead, Updated[A])) -
          App[A].begin();
      for (; i < App[A].size(); i++) Update(App[A][i], 0, 0, Q - 1, 0);
      if (i > 0) Updated[A] = App[A][i - 1];
    } else
      MaxRead = max(MaxRead, A);
    printf("%d\n", Query(MaxRead, NextPos, 0, Q - 1, 0));
  }
}
