#include <iostream>
#include <stdio.h>
#include <vector>
using namespace std;
class Node
{
public:
int nr_a = 0;
int nr_c = 0;
Node* fii[26] {nullptr};
};
class Trie
{
Node* root = nullptr;
public:
void insert(char* s)
{
root = insert_(s, root);
}
void erase(char* s)
{
root = erase_(s, root);
}
int query_prefix(char* s)
{
return query_prefix_(s, root);
}
int query_cuvant(char* s)
{
return query_cuv_(s, root);
}
private:
int query_prefix_(char* s, Node* node);
int query_cuv_(char* s, Node* node);
Node* insert_(char* s, Node* node);
Node* erase_(char* s, Node* node);
};
Node* Trie::insert_(char* s, Node* node)
{
if(node == nullptr)
{
node = new Node();
}
node->nr_a++;
if(s[0] == '\0')
{
node->nr_c++;
return node;
}
else
{
node->fii[s[0] - 'a'] = insert_(s + 1, node->fii[s[0] - 'a']);
}
return node;
}
Node* Trie::erase_(char* s, Node* node)
{
if(node == nullptr)
{
return node;
}
node->nr_a--;
if(s[0] == '\0')
{
node->nr_c--;
}
else
{
node->fii[s[0] - 'a'] = erase_(s + 1, node->fii[s[0] - 'a']);
}
if(node->nr_a == 0)
{
delete node;
node = nullptr;
}
return node;
}
int Trie::query_prefix_(char* s, Node* node)
{
if(s[0] == '\0' || node == nullptr || node->fii[s[0] - 'a'] == nullptr)
return 0;
return query_prefix_(s + 1, node->fii[s[0] - 'a']) + 1;
}
int Trie::query_cuv_(char* s, Node* node)
{
if(node == nullptr)
{
return 0;
}
else if(s[0] == '\0')
return node->nr_c;
else
return query_cuv_(s + 1, node->fii[s[0] - 'a']);
}
Trie arbore;
char s[25];
int main()
{
freopen("trie.in", "r", stdin);
freopen("trie.out", "w", stdout);
while(cin.getline(s, 25))
{
switch(s[0])
{
case '0':
arbore.insert(s + 2);
break;
case '1':
arbore.erase(s + 2);
break;
case '2':
cout<<arbore.query_cuvant(s + 2)<<"\n";
break;
case '3':
cout<<arbore.query_prefix(s + 2)<<"\n";
break;
}
}
}