#include <cstdio>
#include <cstring>
const int LINEMAX = 30;
char s[LINEMAX];
struct Trie {
int cnt, noChildren;
Trie *child[26];
Trie () {
cnt = noChildren = 0;
memset (child, NULL, sizeof (child));
}
};
Trie *T = new Trie;
void insertTrie (Trie *node, char *s) {
if (*s == NULL) {
node-> cnt++;
return;
}
if (node-> child[*s - 'a'] == NULL) {
node-> child[*s - 'a'] = new Trie;
node-> noChildren++;
}
insertTrie (node-> child[*s - 'a'], s + 1);
}
int removeTrie (Trie *node, char *s) {
if (*s == NULL) {
node-> cnt--;
}
else {
if (removeTrie (node-> child[*s - 'a'], s + 1) == 1) { //if the node is deleted
node-> noChildren--;
node-> child[*s - 'a'] = 0;
}
}
if (node-> cnt == 0 && node-> noChildren == 0 && node != T) {
delete node;
return 1;
}
return 0;
}
int countTrie (Trie *node, char *s) {
if (*s == NULL) {
return node-> cnt;
}
if (node-> child[*s - 'a']) {
return countTrie (node-> child[*s - 'a'], s + 1);
}
return 0;
}
int maxPrefixTrie (Trie *node, char *s, int ans = 0) {
if (*s == NULL || !node-> child[*s - 'a']) {
return ans;
}
return maxPrefixTrie (node-> child[*s - 'a'], s + 1, ans + 1);
}
int main () {
freopen ("trie.in", "r", stdin);
freopen ("trie.out", "w", stdout);
gets (s);
while ( !feof (stdin)) {
switch (s[0] - '0') {
case 0: insertTrie (T, s + 2); break;
case 1: removeTrie (T, s + 2); break;
case 2: printf ("%d\n", countTrie (T, s + 2)); break;
case 3: printf ("%d\n", maxPrefixTrie (T, s + 2)); break;
}
gets (s);
}
return 0;
}