#include <bits/stdc++.h>
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
const int block_size = 105;
const long long mod = 1e9 + 7;
const long double eps = 1e-9;
const int inf = mod;
template <typename T>
inline int sign(const T &a) {
  if (a < 0) return -1;
  if (a > 0) return 1;
  return 0;
}
template <typename T>
inline void read(T &x) {
  x = 0;
  T f = 1;
  char ch = getchar();
  while (!isdigit(ch)) {
    if (ch == '-') f = -1;
    ch = getchar();
  }
  while (isdigit(ch)) {
    x = x * 10 + ch - '0';
    ch = getchar();
  }
  x *= f;
}
struct eve {
  int type;
  int time;
  int value;
  int ori;
  int oritime;
  bool operator<(const eve &o) const { return time < o.time; }
};
int id = 0;
const int maxn = 1000010;
int n;
int ans[maxn];
eve q[maxn];
map<int, int> cnt;
void pre() {
  cin >> n;
  id = 0;
  for (long long i = 0; i < n; i++) {
    q[i].oritime = i;
    (read(q[i].type));
    (read(q[i].time));
    (read(q[i].value));
    if (q[i].type == 3) {
      q[i].ori = id++;
    }
  }
}
bool cmp(const eve &a, const eve &b) { return a.oritime < b.oritime; }
void test() {
  for (long long i = 0; i < n; i++) {
    cout << q[i].oritime << ' ';
  }
  cout << endl;
}
void cdq(int l, int r) {
  if (l >= r - 1) return;
  cdq(l, (l + r) / 2);
  int mid = (l + r) / 2;
  cnt.clear();
  sort(q + l, q + r);
  for (long long i = l; i < r; i++) {
    if (q[i].oritime < mid && q[i].type != 3) {
      if (q[i].type == 2) {
        cnt[q[i].value]--;
      } else {
        cnt[q[i].value]++;
      }
      continue;
    }
    if (q[i].oritime >= mid && q[i].type == 3) {
      ans[q[i].ori] += cnt[q[i].value];
    }
  }
  sort(q + l, q + r, cmp);
  cdq((l + r) / 2, r);
}
int main() {
  pre();
  cdq(0, n);
  for (long long i = 0; i < id; i++) {
    cout << ans[i] << endl;
  }
}
