#include <bits/stdc++.h>
using namespace std;
template <typename Arg1>
void __f(const char* name, Arg1&& arg1) {
  cerr << name << " : " << arg1 << std::endl;
}
template <typename Arg1, typename... Args>
void __f(const char* names, Arg1&& arg1, Args&&... args) {
  const char* comma = strchr(names + 1, ',');
  cerr.write(names, comma - names) << " : " << arg1 << " | ";
  __f(comma + 1, args...);
}
struct st {
  map<int, int> tree;
  void update(int node, int start, int end, int time, int val) {
    if (start == end)
      tree[node] = val;
    else {
      int mid = (start + end) / 2;
      if (time <= mid)
        update(2 * node, start, mid, time, val);
      else
        update(2 * node + 1, mid + 1, end, time, val);
      tree[node] = tree[2 * node] + tree[2 * node + 1];
    }
  }
  int query(int node, int start, int end, int l, int r) {
    if (start >= l and end <= r)
      return tree[node];
    else {
      int mid = (start + end) / 2;
      int ans = 0;
      if (l <= mid) ans += query(2 * node, start, mid, l, r);
      if (r > mid) ans += query(2 * node + 1, mid + 1, end, l, r);
      return ans;
    }
  }
};
map<int, st> ans;
int32_t main() {
  int n;
  cin >> n;
  for (int i = 0; i < n; i++) {
    int a, t, x;
    cin >> a >> t >> x;
    if (a == 1) ans[x].update(1, 1, 1e9, t, 1);
    if (a == 2) ans[x].update(1, 1, 1e9, t, -1);
    if (a == 3) cout << ans[x].query(1, 1, 1e9, 1, t) << endl;
  }
  return 0;
}
