#include <fstream>
using namespace std;
const int SIGMA = 26;
const char FIRST = 'a';
const int kLmax = 20;
struct Trie {
Trie *next[SIGMA];
unsigned short contor;
Trie() {
for (int i = 0; i < SIGMA; i++) {
next[i] = NULL;
}
contor = 0;
}
};
void trieInsert(Trie* &node, char *s) {
if (*s == '\0') {
node->contor++;
} else {
if (node->next[*s - FIRST] == NULL) {
node->next[*s - FIRST] = new Trie;
node->next[*s - FIRST]->contor = 0;
}
trieInsert(node->next[*s - FIRST], s + 1);
}
}
int trieQuery(Trie *node, char *s) {
if (*s == '\0') {
return node->contor;
} else {
if (node->next[*s - FIRST] == NULL) {
return 0;
} else {
return trieQuery(node->next[*s - FIRST], s + 1);
}
}
}
bool trieErase(Trie* &node, char *s) {
if (*s == '\0') {
if (node->contor != 0) {
node->contor--;
return 1;
}
} else {
if (node->next[*s - FIRST] != NULL) {
Trie *son = node->next[*s - FIRST];
if (trieErase(son, s + 1) && !son->contor) {
int i = 0;
while ((i < SIGMA) && (son->next[i] == NULL)) {
i++;
}
if (i == SIGMA) {
node->next[*s - FIRST] = NULL;
delete son;
return 1;
}
}
}
}
return 0;
}
int lcp(Trie *node, char *s) {
if (*s == '\0') {
return 0;
} else {
if (node->next[*s - FIRST] != 0) {
return 1 + lcp(node->next[*s - FIRST], s + 1);
}
return 0;
}
}
Trie *Root;
int main(void) {
ifstream in("trie.in");
ofstream out("trie.out");
int opType;
char s[kLmax + 1];
Root = new Trie;
while (in >> opType >> s) {
if (opType == 0) {
trieInsert(Root, s);
} else if (opType == 1) {
trieErase(Root, s);
} else if (opType == 2) {
out << trieQuery(Root, s) << '\n';
} else {
out << lcp(Root, s) << '\n';
}
}
in.close();
out.close();
return 0;
}