Why I have to finish so many assignments???

Jamie is getting very busy with his school life. He starts to forget the assignments that he has to do. He decided to write the things down on a to-do list. He assigns a value priority for each of his assignment (lower value means more important) so he can decide which he needs to spend more time on.

After a few days, Jamie finds out the list is too large that he can't even manage the list by himself! As you are a good friend of Jamie, help him write a program to support the following operations on the to-do list:

  * set ai xi — Add assignment ai to the to-do list if it is not present, and set its priority to xi. If assignment ai is already in the to-do list, its priority is changed to xi. 
  * remove ai — Remove assignment ai from the to-do list if it is present in it. 
  * query ai — Output the number of assignments that are more important (have a smaller priority value) than assignment ai, so Jamie can decide a better schedule. Output  - 1 if ai is not in the to-do list. 
  * undo di — Undo all changes that have been made in the previous di days (not including the day of this operation) 



At day 0, the to-do list is empty. In each of the following q days, Jamie will do exactly one out of the four operations. If the operation is a query, you should output the result of the query before proceeding to the next day, or poor Jamie cannot make appropriate decisions.

Input

The first line consists of a single integer q (1 ≤ q ≤ 105) — the number of operations.

The following q lines consists of the description of the operations. The i-th line consists of the operation that Jamie has done in the i-th day. The query has the following format:

The first word in the line indicates the type of operation. It must be one of the following four: set, remove, query, undo.

  * If it is a set operation, a string ai and an integer xi follows (1 ≤ xi ≤ 109). ai is the assignment that need to be set to priority xi. 
  * If it is a remove operation, a string ai follows. ai is the assignment that need to be removed. 
  * If it is a query operation, a string ai follows. ai is the assignment that needs to be queried. 
  * If it is a undo operation, an integer di follows (0 ≤ di < i). di is the number of days that changes needed to be undone. 



All assignment names ai only consists of lowercase English letters and have a length 1 ≤ |ai| ≤ 15.

It is guaranteed that the last operation is a query operation.

Output

For each query operation, output a single integer — the number of assignments that have a priority lower than assignment ai, or  - 1 if ai is not in the to-do list.

Interaction

If the operation is a query, you should output the result of the query and flush the output stream before proceeding to the next operation. Otherwise, you may get the verdict Idleness Limit Exceed.

For flushing the output stream, please refer to the documentation of your chosen programming language. The flush functions of some common programming languages are listed below:

  * C: fflush(stdout);
  * C++: cout « flush;
  * Java: System.out.flush();

Examples

Input

8
set chemlabreport 1
set physicsexercise 2
set chinesemockexam 3
query physicsexercise
query chinesemockexam
remove physicsexercise
query physicsexercise
query chinesemockexam


Output

1
2
-1
1


Input

8
set physicsexercise 2
set chinesemockexam 3
set physicsexercise 1
query physicsexercise
query chinesemockexam
undo 4
query physicsexercise
query chinesemockexam


Output

0
1
0
-1


Input

5
query economicsessay
remove economicsessay
query economicsessay
undo 2
query economicsessay


Output

-1
-1
-1


Input

5
set economicsessay 1
remove economicsessay
undo 1
undo 1
query economicsessay


Output

-1
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5, MaxStep = 30;
const int maxnode = maxn * MaxStep * 4;
int tot = 0, rot[maxn + 5];
int nx[maxnode + 5][2], cnt[maxnode + 5];
int Upd(int px, int vv, int pp, int del) {
  int x = ++tot;
  nx[x][0] = nx[px][0], nx[x][1] = nx[px][1], cnt[x] = cnt[px] + del;
  if (pp < 0) return x;
  int t = vv >> pp & 1;
  nx[x][t] = Upd(nx[px][t], vv, pp - 1, del);
  return x;
}
int Query(int x, int vv, int pp) {
  if (pp < 0) return 0;
  int t = vv >> pp & 1, rem = 0;
  if (t) rem += cnt[nx[x][0]];
  rem += Query(nx[x][t], vv, pp - 1);
  return rem;
}
int tot2 = 0, rot2[maxn + 5];
int nx2[maxnode + 5][2], col[maxnode + 5];
int Upd2(int px, int vv, int pp, int ccc) {
  int x = ++tot2;
  nx2[x][0] = nx2[px][0], nx2[x][1] = nx2[px][1];
  if (pp < 0) {
    col[x] = ccc;
    return x;
  }
  int t = vv >> pp & 1;
  nx2[x][t] = Upd2(nx2[px][t], vv, pp - 1, ccc);
  return x;
}
int Query2(int x, int vv, int pp) {
  if (pp < 0) return col[x];
  int t = vv >> pp & 1;
  if (nx2[x][t]) return Query2(nx2[x][t], vv, pp - 1);
  return 0;
}
map<string, int> Id;
int GetId(char *buf) {
  static int iid = 0;
  string str(buf);
  if (Id.find(str) == Id.end()) Id[str] = iid++;
  return Id[str];
}
int main() {
  int T, id, x, dd;
  char ord[10], buf[30];
  scanf("%d", &T);
  for (int t = 1; t <= T; ++t) {
    scanf("%s", ord);
    if (ord[0] == 's') {
      scanf("%s%d", buf, &x);
      id = GetId(buf);
      int be = Query2(rot2[t - 1], id, MaxStep - 1), rt = rot[t - 1];
      if (be) rt = Upd(rt, be, MaxStep - 1, -1);
      rot[t] = Upd(rt, x, MaxStep - 1, 1);
      rot2[t] = Upd2(rot2[t - 1], id, MaxStep - 1, x);
    } else if (ord[0] == 'r') {
      scanf("%s", buf);
      id = GetId(buf);
      int be = Query2(rot2[t - 1], id, MaxStep - 1);
      if (be) {
        rot[t] = Upd(rot[t - 1], be, MaxStep - 1, -1);
        rot2[t] = Upd2(rot2[t - 1], id, MaxStep - 1, 0);
      } else
        rot[t] = rot[t - 1], rot2[t] = rot2[t - 1];
    } else if (ord[0] == 'q') {
      rot[t] = rot[t - 1], rot2[t] = rot2[t - 1];
      scanf("%s", buf);
      id = GetId(buf);
      int be = Query2(rot2[t - 1], id, MaxStep - 1);
      printf("%d\n", be ? Query(rot[t - 1], be, MaxStep - 1) : -1);
      fflush(stdout);
    } else {
      scanf("%d", &dd);
      rot[t] = rot[t - dd - 1], rot2[t] = rot2[t - dd - 1];
    }
  }
  return 0;
}
