#include <iostream>
#include <fstream>
#include <stack>
#include <queue>
#include <vector>
#include <map>
#include <cctype>
#include <unordered_map>
#include <cmath>
#include <bitset>
#include <string>
#include <cstring>
#include <algorithm>
using namespace std;
ifstream in("trie.in");
ofstream out("trie.out");
int a,b,c,d,e,f,g,i,j,k,l,m,n,o,q,r,s,S,t,T,x,y,z,ok,nr,w,C,k1,k2,poz,pas,Max,mid,nways,MOD;
const int SIGMA=27;
char str[25];
struct Trie{
Trie* children[SIGMA];
int isWord;
};
Trie* newTrie(){
Trie* answer=new Trie();
answer->isWord = 0;
for(i=0;i<SIGMA;i++){
answer->children[i]=NULL;
}
return answer;
}
void Insert(Trie *root, char *S){
if(S[0]== '\0'){
root->isWord++;
}
else{
if(root->children[S[0]-'a']==NULL){
root->children[S[0]-'a'] = newTrie();
}
Insert(root->children[S[0]-'a'],S+1);
}
}
void Erase(Trie *root,char *S){
if(S[0]== '\0'){
root->isWord--;
}
else{
if(root->children[S[0]-'a']!=NULL){
Erase(root->children[S[0]-'a'],S+1);
}
}
}
int Find(Trie *root,char *S){
if(S[0]=='\0'){
return root->isWord;
}
if(root->children[S[0]-'a']==NULL){
return 0;
}
else return Find(root->children[S[0]-'a'],S+1);
}
int FindPref(Trie *root,char *S,int lvl){
if(S[0]=='\0'){
return lvl;
}
if(root->children[S[0]-'a']==NULL){
return lvl;
}
else return FindPref(root->children[S[0]-'a'],S+1,lvl+1);
}
int main()
{
Trie *root = newTrie();
while(in>>x){
in>>str;
if(x==0){
Insert(root,str);
}
if(x==1){
Erase(root,str);
}
if(x==2){
out<<Find(root,str);
out<<'\n';
}
if(x==3){
k=0;
out<<FindPref(root,str,k);
out<<'\n';
}
}
return 0;
}