#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#define LL long long
#define LDB long double
using namespace std; LDB alpha=0.75;
const LL mo=;
int newadd;
int root=,datcnt,rbcnt,cnt,nodeintree,delnode;
char ans[];
int nd[],nex[];
int rb[];
LL key[]; struct treenode{
int size,lc,rc,num,fa,tim,v,dep;
LL nam; inline bool operator < (const treenode&a) const {
if (num<a.num) return();
if (num>a.num) return();
if (tim>a.tim) return();
return();
} inline bool operator == (const treenode&a) const{
if ((a.num==num)&&(a.tim==tim)&&(a.nam==nam)) return();
return();
}
}tr[],dat[]; LL namhash(char* st){
LL t=,len=strlen(st);
for (int i=;i<len;i++)
t*=,t+=st[i]-'A'+;
return(t);
} int numget(char* st){
int t=,len=strlen(st);
for (int i=;i<len;i++) t*=,t+=st[i]-'';
return(t);
} void namtrans(LL nam){
int cnt=-;LL t=;
while (t<=nam)
t*=,cnt+=; for (int i=cnt;i>=;i--) ans[i]=nam%+'A'-,nam/=;
for (int i=;i<=cnt;i++) putchar(ans[i]);
} int hash_query(LL nam){
int po=nam%mo;
for (int p=nd[po];p!=-;p=nex[p])
if (key[p]==nam) return(p);
nex[++datcnt]=nd[po];nd[po]=datcnt;key[datcnt]=nam;
newadd=;
return(datcnt);
} int getrank(int po,treenode t){
if ((t==tr[po])&&(tr[po].v!=)) return(tr[tr[po].lc].size+tr[po].v);
if (t<tr[po]) return(getrank(tr[po].lc,t));
if (tr[po]<t) return(getrank(tr[po].rc,t)+tr[tr[po].lc].size+tr[po].v);
} LL getkth(int po,int num){
if (num<=tr[tr[po].lc].size) return(getkth(tr[po].lc,num));
if (num>tr[tr[po].lc].size+tr[po].v) return(getkth(tr[po].rc,num-tr[tr[po].lc].size-tr[po].v));
return(tr[po].nam);
} void dfs(int po){
if (tr[po].lc) dfs(tr[po].lc);
if (tr[po].v) rb[++rbcnt]=po;else nodeintree--,delnode--;
if (tr[po].rc) dfs(tr[po].rc);
} void build(int l,int r){
int mid=(l+r)>>,po=rb[(l+r)/]; if (l<mid){
tr[po].lc=rb[(l+mid-)/];
tr[rb[(l+mid-)/]].fa=po;
tr[rb[(l+mid-)/]].dep=tr[po].dep+;
build(l,mid-);
}else tr[po].lc=;
if (r>mid){
tr[po].rc=rb[(r+mid+)/];
tr[rb[(r+mid+)/]].fa=po;
tr[rb[(r+mid+)/]].dep=tr[po].dep+;
build(mid+,r);
}else tr[po].rc=;
tr[po].size=tr[tr[po].lc].size+tr[tr[po].rc].size+tr[po].v;
} void rebuild(int po){
rbcnt=;dfs(po); if (po!=root){
tr[rb[(rbcnt+)/]].fa=tr[po].fa;
tr[rb[(rbcnt+)/]].dep=tr[tr[po].fa].dep+;
if (po==tr[tr[po].fa].lc) tr[tr[po].fa].lc=rb[(rbcnt+)/];
else tr[tr[po].fa].rc=rb[(rbcnt+)/];
}else {root=rb[(rbcnt+)/];tr[rb[(rbcnt+)/]].fa=;tr[rb[(rbcnt+)/]].dep=;} build(,rbcnt);
} void scapegoat_insert(int num){
nodeintree++;
if ((tr[root].size==)&&(tr[root].lc==)&&(tr[root].rc==)) {
root=++cnt;tr[root]=dat[num];tr[root].dep=;
tr[cnt].v=;tr[cnt].size=;
return;
}
int po=root;
while (){
tr[po].size++; if (dat[num]==tr[po]) {tr[po].v++;break;} if (dat[num]<tr[po]){
if (tr[po].lc==){
tr[++cnt]=dat[num];
tr[cnt].fa=po;
tr[po].lc=cnt;
tr[cnt].dep=tr[po].dep+;
tr[cnt].v=;tr[cnt].size=;
break;
}else {po=tr[po].lc;continue;}
} if (tr[po]<dat[num]){
if (tr[po].rc==){
tr[++cnt]=dat[num];
tr[cnt].fa=po;
tr[po].rc=cnt;
tr[cnt].dep=tr[po].dep+;
tr[cnt].v=;tr[cnt].size=;
break;
}else {po=tr[po].rc;continue;}
}
} if (tr[po].dep>(log(tr[root].size)/log(/alpha))){
int dp=tr[po].dep;
while ((dp-tr[po].dep)<=(log(tr[po].size)/log(/alpha))) po=tr[po].fa;
rebuild(po);
}
} void scapegoat_delete(int num){
int po=root;
while (){
tr[po].size--;
if (tr[po]<dat[num]) {po=tr[po].rc;continue;}
if (dat[num]<tr[po]) {po=tr[po].lc;continue;}
if (tr[po]==dat[num]) {tr[po].v--;if (tr[po].v==) delnode++;break;}
}
if (delnode>nodeintree/) rebuild(root);
} int main(){ freopen("a.in","r",stdin); int n;char st[];
scanf("%d",&n); for (int i=;i<=;i++) nd[i]=-; for (int i=;i<=n;i++){
scanf("%s",st); if (st[]=='+'){
LL nam=namhash(st);
newadd=;
int po=hash_query(nam);
if (!newadd) {
scapegoat_delete(po);
dat[po].nam=nam;scanf("%d",&dat[po].num);dat[po].tim=i;
scapegoat_insert(po);
}else{
dat[po].nam=nam;scanf("%d",&dat[po].num);dat[po].tim=i;
scapegoat_insert(po);
}
} if ((st[]=='?')&&(st[]<='Z')&&(st[]>='A')){
LL nam=namhash(st);
int po=hash_query(nam);
printf("%d\n",datcnt-getrank(root,dat[po])+);
} if ((st[]=='?')&&(st[]<='')&&(st[]>='')){
int po=numget(st);
for (int i=po;i<=min(po+,datcnt);i++) {
namtrans(getkth(root,datcnt-i+));
if (i!=min(po+,datcnt))printf(" ");
}
printf("\n");
}
}
}