#include <fstream>
#include <algorithm>
#include <vector>
#include <cstring>
using namespace std;
ifstream cin("trie.in");
ofstream cout("trie.out");
const int ALPHABET_SIZE = 26;
struct TrieNode
{
TrieNode *children[26];
int word_endings;
TrieNode()
{
for (int i = 0; i < ALPHABET_SIZE; i++)
this->children[i] = nullptr;
this->word_endings = 0;
}
};
void insert_word(TrieNode *current, char word[])
{
for (int i = 0; word[i] != 0; i++)
{
if (current->children[word[i] - 'a'] == nullptr)
{
current->children[word[i] - 'a'] = new TrieNode();
}
current = current->children[word[i] - 'a'];
}
current->word_endings++;
}
int word_lookup(TrieNode *current, char word[])
{
for (int i = 0; word[i] != 0; i++)
{
if (current->children[word[i] - 'a'] == nullptr)
return -1;
current = current->children[word[i] - 'a'];
}
return current->word_endings;
}
bool has_children(TrieNode *current)
{
for (int i = 0; i < ALPHABET_SIZE; i++)
if (current->children[i] != nullptr)
return 1;
return 0;
}
void delete_word(TrieNode *¤t, char word[], int height = 0)
{
if (strlen(word) == height)
{
if (current->word_endings >= 1)
current->word_endings--;
if (current->word_endings == 0 && !has_children(current))
{
delete current;
current = nullptr;
return;
}
}
else if (current->children[word[height] - 'a'] != nullptr)
{
delete_word(current->children[word[height] - 'a'], word, height + 1);
}
if (!has_children(current) && current->word_endings == 0)
{
delete current;
current = nullptr;
}
}
int longest_common_prefix(TrieNode *current, char word[])
{
int i;
for (i = 0; word[i] != 0; i++)
{
if (current->children[word[i] - 'a'] != nullptr)
{
current = current->children[word[i] - 'a'];
}
else
return i;
}
return i;
}
int main()
{
int op;
TrieNode *root = new TrieNode();
char s[100];
while (cin >> op >> s)
{
if (op == 0)
{
insert_word(root, s);
}
else if (op == 1)
{
delete_word(root, s);
}
else if (op == 2)
{
cout << word_lookup(root, s) << '\n';
}
else if (op == 3)
{
cout << longest_common_prefix(root, s) << '\n';
}
}
return 0;
}