#include <fstream>
#include <vector>
#include <unordered_map>
using namespace std;
ifstream fin("trie.in");
ofstream fout("trie.out");
class Trie{
private:
unordered_map<char, Trie*> edge;
int cnt = 0;
int cntFinal = 0;
inline Trie* getEdge(char ch){
auto it = edge.find(ch);
if(it != edge.end())
return it->second;
return nullptr;
}
inline Trie* addEdge(char ch){
Trie* edg = getEdge(ch);
if(edg == nullptr){
edge.insert({ch, new Trie()});
edg = edge[ch];
}
return edg;
}
bool isFinal(){
return cntFinal;
}
public:
void insert(const char* word){
int i = 0;
++this->cnt;
Trie* current = this;
while(word[i]){
current = current->addEdge(word[i]);
++current->cnt;
++i;
}
++current->cntFinal;
}
void erase(const char* word){
int i = 0;
Trie* current = this;
while(word[i]){
current = current->getEdge(word[i]);
--current->cnt;
++i;
}
if(current->cnt == 0){
i = 0;
Trie* ant;
current = this;
while(word[i] && current->cnt > 0){
ant = current;
current = current->getEdge(word[i]);
++i;
}
ant->edge.erase(word[i - 1]);
delete current;
}
}
int count(const char* word){
int i = 0;
Trie* current = this;
while(word[i] && current != nullptr){
current = current->getEdge(word[i]);
++i;
}
if(current != nullptr && current->isFinal())
return current->cntFinal;
else
return 0;
}
int longestPrefix(const char* word){
int i = 0;
Trie* current = this;
while(word[i] && current != nullptr && current->cnt > 0){
current = current->getEdge(word[i]);
++i;
}
return i - 1;
}
};
const int STRLEN_MAX = 20;
int op;
char word[STRLEN_MAX + 1];
Trie trie;
int main(){
while(fin >> op >> word)
switch(op){
case 0:{
trie.insert(word);
break;
}
case 1:{
trie.erase(word);
break;
}
case 2:{
fout << trie.count(word) << '\n';
break;
}
case 3:{
fout << trie.longestPrefix(word) << '\n';
break;
}
}
fin.close();
fout.close();
return 0;
}