#include <fstream>
#include <string>
using namespace std;
struct nod{
nod *fi[26];
bool isL;
int wordCount;
nod()
{
isL = false;
wordCount = 0;
for(int i = 0 ; i < 26 ; i++)
fi[i] = nullptr;
}
};
void ins(nod *r, const string& key)
{
nod *curr = r;
for(char c : key)
{
if(curr->fi[c - 'a'] == nullptr)
{
nod *newNod = new nod();
curr->fi[c - 'a'] = newNod;
}
curr = curr->fi[c - 'a'];
}
curr->isL = true;
curr->wordCount++;
}
bool search(nod *r, const string& key)
{
nod *curr = r;
for(char c : key)
{
if(curr->fi[c - 'a'] == nullptr)
return false;
curr = curr->fi[c - 'a'];
}
return curr->isL;
}
bool isEmpty(nod *r)
{
for(int i = 0 ; i < 26 ; i++)
if(r->fi[i])
return false;
return true;
}
bool del(nod* r, const string& key, int depth = 0) {
if (!r)
return false;
if (depth == key.size()) {
if (r->wordCount > 0)
r->wordCount--;
return isEmpty(r) && r->wordCount == 0;
}
int ind = key[depth] - 'a';
if (del(r->fi[ind], key, depth + 1)) {
delete r->fi[ind];
r->fi[ind] = nullptr;
return isEmpty(r) && r->wordCount == 0;
}
return false;
}
int count(nod *r, const string& key)
{
nod *curr = r;
for(auto c : key)
{
if(curr->fi[c - 'a'] == nullptr)
return 0;
curr = curr->fi[c - 'a'];
}
return curr->isL ? curr->wordCount : 0;
}
int longestCommonPrefixLength(nod *r, const string& w)
{
nod *curr = r;
int length = 0;
for(char c : w)
{
int index = c - 'a';
if(curr->fi[index] == nullptr)
break;
curr = curr->fi[index];
length++;
}
return length;
}
int main()
{
ifstream fin("trie.in");
ofstream fout("trie.out");
nod *r = new nod();
int op;
string word;
while(fin >> op >> word)
{
if(op == 0)
ins(r, word);
if(op == 1)
del(r, word);
if(op == 2)
fout << count(r, word) << '\n';
if(op == 3)
fout << longestCommonPrefixLength(r, word) << '\n';
}
return 0;
}