#include <bits/stdc++.h>
using namespace std;
struct TQuery {
  int type, tme, x;
};
const int N = 1e5 + 2;
int q, n, m, a[N], b[N];
TQuery p[N];
class TTree {
  struct TNode {
    int sum = 0;
    TNode *lc = nullptr, *rc = nullptr;
  };
  TNode *root;
  void Update(TNode *&node, int sl, int sr, int u, int v) {
    if (!node) node = new TNode;
    node->sum += v;
    if (sl < sr) {
      int mid = (sl + sr) / 2;
      if (u <= mid)
        Update(node->lc, sl, mid, u, v);
      else
        Update(node->rc, mid + 1, sr, u, v);
    }
  }
  int Query(TNode *&node, int sl, int sr, int ql, int qr) {
    if (!node || qr < sl || sr < ql) return 0;
    if (ql <= sl && sr <= qr) return node->sum;
    int mid = (sl + sr) / 2;
    return Query(node->lc, sl, mid, ql, qr) +
           Query(node->rc, mid + 1, sr, ql, qr);
  }

 public:
  void Update(int u, int v) { Update(root, 1, n, u, v); }
  int Query(int l, int r) { return Query(root, 1, n, l, r); }
} tree[N];
int Get(int a[], int n, int x) { return lower_bound(a, a + n, x) - a + 1; }
void Solve() {
  sort(a, a + n);
  n = unique(a, a + n) - a;
  sort(b, b + m);
  m = unique(b, b + m) - b;
  for (int i = 0; i < q; ++i) {
    int type = p[i].type, tme = Get(a, n, p[i].tme), x = Get(b, m, p[i].x);
    if (type == 1)
      tree[x].Update(tme, 1);
    else if (type == 2)
      tree[x].Update(tme, -1);
    else
      printf("%d\n", tree[x].Query(1, tme));
  }
}
int main() {
  scanf("%d", &q);
  for (int i = 0; i < q; ++i) {
    int type, tme, x;
    scanf("%d%d%d", &type, &tme, &x);
    p[i] = {type, tme, x};
    a[n++] = tme;
    b[m++] = x;
  }
  Solve();
  return 0;
}
