#include <bits/stdc++.h>
using namespace std;
struct treap {
  int x, y, sz;
  treap* l;
  treap* r;
};
treap* create_treap(int x) {
  treap* t = new treap();
  t->x = x;
  t->y = rand();
  t->l = nullptr;
  t->r = nullptr;
  t->sz = 1;
  return t;
}
void print(treap* t) {
  if (!t) return;
  if (!t->l && !t->r) {
    cout << "Empty vertex " << t->x << endl;
    return;
  }
  cout << "---Start of the vertex " << t->x << "---" << endl;
  if (t->l) {
    cout << "Left of the " << t->x << " :" << endl;
    print(t->l);
  } else
    cout << "Empty left of " << t->x << " :" << endl;
  if (t->r) {
    cout << "Right of the " << t->x << ": " << endl;
    print(t->r);
  } else
    cout << "Empty right of " << t->x << ": " << endl;
  cout << "---End of the vertex " << t->x << "---" << endl;
}
int get_sz(treap* t) {
  if (!t) return 0;
  return t->sz;
}
void upd(treap* t) { t->sz = get_sz(t->l) + get_sz(t->r) + 1; }
pair<treap*, treap*> Split(treap* t, int x) {
  if (!t) return {0, 0};
  if (t->x <= x) {
    pair<treap*, treap*> sp = Split(t->r, x);
    t->r = sp.first;
    upd(t);
    return {t, sp.second};
  }
  pair<treap*, treap*> sp = Split(t->l, x);
  t->l = sp.second;
  upd(t);
  return {sp.first, t};
}
treap* Merge(treap* first, treap* second) {
  if (!first) return second;
  if (!second) return first;
  if (first->y > second->y) {
    if (first->x < second->x)
      first->r = Merge(first->r, second);
    else
      first->l = Merge(first->l, second);
    upd(first);
    return first;
  }
  if (second->x < first->x)
    second->r = Merge(second->r, first);
  else
    second->l = Merge(second->l, first);
  upd(second);
  return second;
}
void add(treap*& root, int x) {
  pair<treap*, treap*> sp = Split(root, x);
  treap* second = create_treap(x);
  treap* tmp = Merge(sp.first, second);
  root = Merge(tmp, sp.second);
}
int get_col(treap*& root, int x) {
  pair<treap*, treap*> sp = Split(root, x);
  int ans = get_sz(sp.first);
  root = Merge(sp.first, sp.second);
  return ans;
}
void solve() {
  int m;
  cin >> m;
  set<int> second;
  int type, t, c;
  vector<vector<int> > a(m, vector<int>(3));
  for (int i = 0; i < m; i++) {
    cin >> type >> t >> c;
    a[i] = {type, t, c};
    second.insert(c);
  }
  map<int, int> compress;
  int index = 0;
  for (auto x : second) {
    compress[x] = index++;
  }
  int n = index, i;
  vector<treap*> added(n, 0), deleted(n, 0);
  for (auto x : a) {
    type = x[0];
    t = x[1];
    i = compress[x[2]];
    if (type == 1)
      add(added[i], t);
    else if (type == 2)
      add(deleted[i], t);
    else
      cout << get_col(added[i], t) - get_col(deleted[i], t) << '\n';
  }
}
signed main() {
  srand(time(0));
  ios_base::sync_with_stdio(false);
  cin.tie(0);
  int t = 1;
  while (t--) {
    solve();
  }
  return 0;
}
