#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5, MI = 1e6;
int read() {
  static streambuf* in = cin.rdbuf();
  static char buf[MI], *p1, *p2;
  int c = (p1 == p2 && (p2 = (p1 = buf) + in->sgetn(buf, MI), p1 == p2)
               ? -1
               : *p1++),
      r = 0;
  while (c < 48)
    c = (p1 == p2 && (p2 = (p1 = buf) + in->sgetn(buf, MI), p1 == p2) ? -1
                                                                      : *p1++);
  while (c > 47)
    r = (r << 3) + (r << 1) + (c & 15),
    c = (p1 == p2 && (p2 = (p1 = buf) + in->sgetn(buf, MI), p1 == p2) ? -1
                                                                      : *p1++);
  return r;
}
void wrt(int x) {
  static streambuf* out = cout.rdbuf();
  static char ch[11];
  int sz = 0;
  if (!x)
    out->sputc(48);
  else {
    while (x) ch[++sz] = x % 10, x /= 10;
    while (sz) out->sputc(ch[sz--] + 48);
  }
  out->sputc(10);
}
struct Qry {
  int a, t, x;
} q[N];
int n, gt[N], gx[N], sz, T[N], ls[N * 17], rs[N * 17], cnt[N * 17];
void upd(int p, int v, int l, int r, int& o) {
  cnt[o ? o : o = ++sz] += v;
  if (l == r) return;
  int mid = (l + r) >> 1;
  if (p <= mid)
    upd(p, v, l, mid, ls[o]);
  else
    upd(p, v, mid + 1, r, rs[o]);
}
int qry(int p, int l, int r, int o) {
  if (r <= p) return cnt[o];
  int mid = (l + r) >> 1, ret = qry(p, l, mid, ls[o]);
  return ret + (p > mid ? qry(p, mid + 1, r, rs[o]) : 0);
}
int main() {
  ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
  n = read();
  for (int i = (1); i <= (n); i++)
    q[i].a = read(), gt[i] = q[i].t = read(), gx[i] = q[i].x = read();
  sort(gt + 1, gt + n + 1), sort(gx + 1, gx + n + 1);
  for (int i = (1); i <= (n); i++) {
    int t = lower_bound(gt + 1, gt + n + 1, q[i].t) - gt,
        x = lower_bound(gx + 1, gx + n + 1, q[i].x) - gx;
    if (q[i].a == 3)
      wrt(qry(t, 1, n, T[x]));
    else
      upd(t, q[i].a == 1 ? 1 : -1, 1, n, T[x]);
  }
  return 0;
}
