#include <bits/stdc++.h>
const int MAXN = 1e5;
using namespace std;
inline void read(int &x) {
  x = 0;
  char c = getchar();
  while (!isdigit(c)) c = getchar();
  while (isdigit(c)) {
    x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
  }
}
void write(int x) {
  static char sta[10];
  static int top;
  while (sta[top++] = x % 10 ^ 48, x /= 10) continue;
  while (top) putchar(sta[--top]);
  putchar('\n');
}
struct Node {
  int opt, t, x;
  Node() {}
} q[MAXN + 5];
int n1, n2, m;
struct FenwickTree {
  map<int, int> c[MAXN + 5];
  int lowbit(int x) { return x & (-x); }
  void modify(int t, int k, int val) {
    for (; t <= n1; t += lowbit(t)) c[t][k] += val;
  }
  int query(int t, int k) {
    int ret = 0;
    for (; t; t -= lowbit(t)) ret += c[t][k];
    return ret;
  }
} Ft;
int tmp1[MAXN + 5], tmp2[MAXN + 5];
void init() {
  read(m);
  for (int i = 1; i <= m; ++i) {
    read(q[i].opt), read(q[i].t), read(q[i].x);
    tmp1[i] = q[i].t, tmp2[i] = q[i].x;
  }
  sort(tmp1 + 1, tmp1 + 1 + m), sort(tmp2 + 1, tmp2 + 1 + m);
  n1 = unique(tmp1 + 1, tmp1 + 1 + m) - (tmp1 + 1);
  n2 = unique(tmp2 + 1, tmp2 + 1 + m) - (tmp2 + 1);
  for (int i = 1; i <= m; ++i) {
    q[i].t = lower_bound(tmp1 + 1, tmp1 + 1 + n1, q[i].t) - tmp1;
    q[i].x = lower_bound(tmp2 + 1, tmp2 + 1 + n2, q[i].x) - tmp2;
  }
}
int main() {
  init();
  for (int i = 1; i <= m; ++i) {
    if (q[i].opt == 1) {
      Ft.modify(q[i].t, q[i].x, 1);
    } else if (q[i].opt == 2) {
      Ft.modify(q[i].t, q[i].x, -1);
    } else {
      write(Ft.query(q[i].t, q[i].x));
    }
  }
  return 0;
}
