//#pragma GCC optimize ("O3")
//#pragma GCC target ("sse4")
#include <bits/stdc++.h>
using namespace std;
FILE *fin = freopen("trie.in", "r", stdin);
FILE *fout = freopen("trie.out","w",stdout);
static const int MAX_LEN = 20+5;
const int TETA = 26;
struct TrieNode
{
TrieNode *sons[TETA];
int wordCount, wordEndingCount;
TrieNode()
{
this->wordCount = this->wordEndingCount = 0;
for(int i = 0; i < TETA; ++i)
{
this->sons[i] = NULL;
}
}
};
TrieNode *root = new TrieNode();
void Insert(TrieNode *node,char *word)
{
node->wordCount++;
if(*word == NULL)
{
node->wordEndingCount++; return;
}
if(node->sons[*word - 'a'] == NULL)
{
node->sons[*word-'a'] = new TrieNode;
}
Insert(node->sons[*word -'a'], word+1);
}
void Erase(TrieNode *node, char *word)
{
node->wordCount--;
if(*word == NULL)
{
node->wordEndingCount--;
return;
}
Erase(node->sons[*word - 'a'], word+1);
}
int CountApparitions(TrieNode *node, char *word)
{
if(*word == NULL)
{
return node->wordEndingCount;
}
if(node->sons[*word - 'a'] == NULL)
{
return 0;
}
return CountApparitions(node->sons[*word - 'a'], word+1);
}
int MaxCommonLength(TrieNode *node, char *word, int currentLength)
{
if(*word == NULL || node->sons[*word - 'a'] == NULL || node->sons[*word - 'a']-> wordCount == 0)
{
return currentLength;
}
else
{
return MaxCommonLength(node->sons[*word - 'a'],word+1,currentLength+1);
}
}
int main()
{
ios_base::sync_with_stdio(0);
int type;
char word[MAX_LEN];
while(scanf("%d%s", &type, word) == 2)
{
if(type == 0)
{
Insert(root, word);
}
else if(type == 1)
{
Erase(root,word);
}
else if(type == 2)
{
printf("%d\n",CountApparitions(root,word));
}
else
{
printf("%d\n",MaxCommonLength(root,word,0));
}
}
return 0;
}