#include <bits/stdc++.h>
using namespace std;
const int sz = 1e5 + 5;
vector<tuple<int, int, int> > q;
vector<int> FWT[sz];
int mt[sz];
vector<int> mapt[sz];
void update(int idx, int v, int pn) {
  vector<int>& x = FWT[v];
  while (idx < x.size()) {
    x[idx] += pn;
    idx = idx + (idx & -idx);
  }
}
int query(int idx, int v) {
  vector<int>& x = FWT[v];
  int ans = 0;
  while (idx > 0) {
    ans += x[idx];
    idx = idx - (idx & -idx);
  }
  return ans;
}
int main() {
  int n;
  cin >> n;
  map<int, int> values;
  int vv = 1;
  for (int i = 0; i < n; ++i) {
    tuple<int, int, int> x;
    cin >> get<0>(x) >> get<1>(x) >> get<2>(x);
    if (values[get<2>(x)] == 0) {
      values[get<2>(x)] = vv++;
    }
    get<2>(x) = values[get<2>(x)];
    q.push_back(x);
    mapt[get<2>(x)].push_back(get<1>(x));
  }
  for (int i = 1; i < vv; ++i) {
    sort(mapt[i].begin(), mapt[i].end());
    FWT[i].resize(unique(mapt[i].begin(), mapt[i].end()) - mapt[i].begin() + 2);
  }
  for (int i = 0; i < n; ++i) {
    int a = get<0>(q[i]);
    int t = get<1>(q[i]);
    int x = get<2>(q[i]);
    t = lower_bound(mapt[x].begin(), mapt[x].end(), t) - mapt[x].begin() + 1;
    if (a == 1) {
      update(t, x, 1);
    } else if (a == 2) {
      update(t, x, -1);
    } else {
      cout << query(t, x) << endl;
    }
  }
}
