#include <cstdio>
#include <cstring>
const int SIGMA = 26;
using namespace std;
int K; char String[SIGMA];
struct trie {
int cnt_words;
int cnt_children;
trie *children[SIGMA];
trie () {
cnt_words = NULL;
cnt_children = NULL;
for( int i = 0; i < SIGMA; i ++ )
children[i] = NULL;
}
}; trie *Root = new trie;
void insert_word( trie *Node, char *String ) {
if( *String == 0 ) {
Node -> cnt_words ++;
return;
}
if( Node -> children[*String - 'a'] == NULL ) {
Node -> children[*String - 'a'] = new trie;
Node -> cnt_children ++;
}
insert_word( Node -> children[*String - 'a'], String + 1 );
return;
}
int delete_word( trie *Node, char *String ) {
if( *String == 0 ) Node -> cnt_words --; else
if( delete_word( Node -> children[*String - 'a'], String + 1 ) ) {
Node -> children[*String - 'a'] = NULL;
Node -> cnt_children --;
}
if( Node -> cnt_words == NULL && Node -> cnt_children == NULL && Node != Root ) {
delete Node;
return 1;
}
return 0;
}
int count_word( trie *Node, char *String ) {
if( *String == 0 )
return Node -> cnt_words;
if( Node -> children[*String - 'a'] != NULL )
return count_word( Node -> children[*String - 'a'], String + 1 );
return 0;
}
int longest_prefix( trie *Node, char *String, int prefix_length ) {
if( *String == 0 )
return prefix_length;
if( Node -> children[*String - 'a'] != NULL )
return longest_prefix( Node -> children[*String - 'a'], String + 1, prefix_length + 1 );
return prefix_length;
}
int main () {
freopen ("trie.in" ,"r", stdin );
freopen ("trie.out","w", stdout);
while( scanf( "%d", &K ) ) {
scanf( "%s", String );
if( String[0] == 0 )
break;
switch( K ) {
case 0: {
insert_word( Root, String );
break;
}
case 1: {
delete_word( Root, String );
break;
}
case 2: {
printf( "%d\n", count_word( Root, String ) );
break;
}
case 3: {
printf( "%d\n", longest_prefix( Root, String, 0 ) );
break;
}
}
memset( String, 0, sizeof( String ) );
}
return 0;
}