#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;
const int maxk = 500 + 5;
const int inf = 1e9 + 7;
long long n, m, k;
map<int, int> s[maxn];
map<int, int> num;
int tot = 1;
int cnt = 1;
struct node {
  int a, b, c;
  int id;
  int answer;
  node() { answer = 0; }
} t[maxn];
int ts[maxn];
int color;
inline int low_bit(int x) { return x & (-x); }
inline void upd(int p, int x) {
  int k = s[color][p];
  while (k < cnt) {
    ts[k] += x;
    k += low_bit(k);
  }
  return;
}
inline int query(int x) {
  int to = s[color][x];
  int ans = 0;
  while (to > 0) {
    ans += ts[to];
    to -= low_bit(to);
  }
  return ans;
}
bool cmp1(node x, node y) {
  if (x.c != y.c) {
    return x.c < y.c;
  } else if (x.b != y.b) {
    return x.b < y.b;
  } else
    return x.id < y.id;
}
bool cmp(node x, node y) {
  if (x.c != y.c) {
    return x.c < y.c;
  } else
    return x.id < y.id;
}
bool cmp2(node x, node y) { return x.id < y.id; }
int main() {
  map<int, int>::iterator iter;
  cin >> n;
  for (int i = 1; i <= n; i++) {
    scanf("%d%d%d", &t[i].a, &t[i].b, &t[i].c);
    t[i].id = i;
  }
  for (int i = 1; i <= n; i++) {
    if (num.find(t[i].c) == num.end()) {
      num.insert(make_pair(t[i].c, tot++));
    }
    int p = num[t[i].c];
    if (s[p].find(t[i].b) == s[p].end()) {
      s[p].insert(make_pair(t[i].b, s[p].size() + 1));
    }
  }
  sort(t + 1, t + 1 + n, cmp1);
  for (int i = 1; i <= n; i++) {
    if (t[i].c != t[i - 1].c) {
      color = num[t[i].c];
      cnt = s[color].size() + 1;
      for (register int j = 1; j < cnt; j++) ts[j] = 0;
    }
    if (t[i].a == 1) {
      upd(t[i].b, 1);
    } else if (t[i].a == 2) {
      upd(t[i].b, -1);
    } else {
      int ans = query(t[i].b);
      t[i].answer = ans;
    }
  }
  sort(t + 1, t + 1 + n, cmp2);
  for (int i = 1; i <= n; i++) {
    if (t[i].a == 3) {
      printf("%d\n", t[i].answer);
    }
  }
  return 0;
}
