#include <bits/stdc++.h>
#pragma GCC optimize("O3")
#pragma GCC target("sse4")
using namespace std;
template <typename dataT>
struct nodeT {
  dataT val;
  nodeT<dataT> *left, *right;
  nodeT() {
    left = nullptr;
    right = nullptr;
    val = dataT();
  }
  nodeT(dataT v) {
    nodeT();
    val = v;
  }
  dataT get_val() { return val; }
  void set_val(dataT x) { val = x; }
  void add_to_val(dataT x) { val = val + x; }
  void update() {
    val = dataT();
    if (left) val = val + left->get_val();
    if (right) val = val + right->get_val();
  }
};
template <typename dataT, typename boundT = int, boundT leftBound = 0,
          boundT rightBound = 100100>
struct dynamic_tree {
  using node = nodeT<dataT>;
  virtual node *get_node(node *before) {
    if (before) return before;
    node *new_node = new node();
    return new_node;
  }
  node *root;
  void clear() { root = nullptr; }
  dynamic_tree() { clear(); }
  node *get_root() { return root; }
  node *set_pos(node *cur, boundT l, boundT r, boundT pos, dataT val) {
    cur = get_node(cur);
    if (l == r)
      cur->set_val(val);
    else {
      boundT mid = (l + r) >> 1;
      if (pos <= mid)
        cur->left = set_pos(cur->left, l, mid, pos, val);
      else
        cur->right = set_pos(cur->right, mid + 1, r, pos, val);
      cur->update();
    }
    return cur;
  }
  node *set_pos(boundT pos, dataT val) {
    root = set_pos(root, leftBound, rightBound, pos, val);
    return root;
  }
  node *set_pos(node *rt, boundT pos, dataT val) {
    return set_pos(rt, leftBound, rightBound, pos, val);
  }
  node *add_to_pos(node *cur, boundT l, boundT r, boundT pos, dataT val) {
    cur = get_node(cur);
    if (l == r)
      cur->add_to_val(val);
    else {
      boundT mid = (l + r) >> 1;
      if (pos <= mid)
        cur->left = add_to_pos(cur->left, l, mid, pos, val);
      else
        cur->right = add_to_pos(cur->right, mid + 1, r, pos, val);
      cur->update();
    }
    return cur;
  }
  node *add_to_pos(boundT pos, dataT val) {
    root = add_to_pos(root, leftBound, rightBound, pos, val);
    return root;
  }
  node *add_to_pos(node *rt, boundT pos, dataT val) {
    return add_to_pos(rt, leftBound, rightBound, pos, val);
  }
  dataT query(node *cur, boundT l, boundT r, boundT x, boundT y) {
    if (cur == nullptr || l > y || r < x) return dataT();
    if (x <= l && r <= y) return cur->get_val();
    boundT mid = (l + r) >> 1;
    if (y <= mid) return query(cur->left, l, mid, x, y);
    if (x > mid) return query(cur->right, mid + 1, r, x, y);
    return query(cur->left, l, mid, x, y) + query(cur->right, mid + 1, r, x, y);
  }
  dataT query(boundT x, boundT y) {
    return query(root, leftBound, rightBound, x, y);
  }
  dataT query(node *rt, boundT x, boundT y) {
    return query(rt, leftBound, rightBound, x, y);
  }
};
template <typename dataT, typename boundT = int, boundT leftBound = 0,
          boundT rightBound = 100100>
struct persistent_tree : dynamic_tree<dataT, boundT, leftBound, rightBound> {
  using node = nodeT<dataT>;
  node *get_node(node *before) override {
    node *new_node = new node();
    if (before) {
      new_node->left = before->left;
      new_node->right = before->right;
      new_node->val = before->val;
    }
    return new_node;
  }
  persistent_tree() : dynamic_tree<dataT, boundT, leftBound, rightBound>() {}
};
using node = nodeT<int>;
char o[55], s[33];
map<string, int> hashe;
int cnt = 1;
int get_id(string &s) {
  auto it = hashe.find(s);
  if (it != hashe.end()) return it->second;
  return hashe[s] = cnt++;
}
int main() {
  const int maxR = 1000000100;
  persistent_tree<int, int, 0, maxR> tr;
  persistent_tree<int, int, 0, 100100> Map;
  node *root = nullptr;
  node *root_map = nullptr;
  int q;
  scanf("%d", &q);
  vector<node *> rts;
  rts.push_back(root);
  vector<node *> rts_map;
  rts_map.push_back(root_map);
  while (q--) {
    scanf("%s", o);
    if (o[0] == 's') {
      scanf("%s", s);
      int x;
      scanf("%d", &x);
      string ss = s;
      int id = get_id(ss);
      int cur_val = Map.query(root_map, id, id);
      if (cur_val) {
        root = tr.add_to_pos(root, cur_val, -1);
      }
      root_map = Map.set_pos(root_map, id, x);
      root = tr.add_to_pos(root, x, 1);
    } else if (o[0] == 'r') {
      scanf("%s", s);
      string ss = s;
      int id = get_id(ss);
      int cur_val = Map.query(root_map, id, id);
      if (cur_val) {
        root_map = Map.set_pos(root_map, id, 0);
        root = tr.add_to_pos(root, cur_val, -1);
      }
    } else if (o[0] == 'q') {
      scanf("%s", s);
      string ss = s;
      int id = get_id(ss);
      int cur_val = Map.query(root_map, id, id);
      if (cur_val) {
        printf("%d\n", tr.query(root, 0, cur_val - 1));
      } else
        printf("-1\n");
    } else if (o[0] == 'u') {
      int d;
      scanf("%d", &d);
      root = rts[rts.size() - 1 - d];
      root_map = rts_map[rts.size() - 1 - d];
    } else
      assert(0);
    rts.push_back(root);
    rts_map.push_back(root_map);
    fflush(stdout);
  }
  return 0;
}
