#include <bits/stdc++.h>
#define pb push_back
using namespace std;
ifstream f("trie.in");
ofstream g("trie.out");
typedef long long ll;
typedef pair<int,int> pi;
int t,T;
class Node
{
#define ABC 26
private:
int occ,fii;
Node* next[ABC];
public:
Node():occ{0},fii{0}{
for(int i=0;i<ABC;i++) next[i]=NULL;
}
int get_occ() const noexcept{
return occ;
}
int get_fii() const noexcept{
return fii;
}
Node* get_ptr_letter(char letter) const noexcept{
return next[letter-'a'];
}
void set_next_letter(char letter,Node* ptr){
if(ptr==NULL && next[letter-'a']!=NULL) fii--;
else
if(ptr!=NULL && next[letter-'a']==NULL) fii++;
next[letter-'a']=ptr;
}
void inc_occ(){
occ++;
}
void dec_occ(){
occ--;
}
~Node()=default;
};
Node* root;
//rad-radacina de care o sa mi leg caracterul de pe pozitia poza
void add_word(Node* rad,const string& S,int poz)
{
if(poz==S.size())
{
rad->inc_occ();
return;
}
char letter=S[poz];
if(rad->get_ptr_letter(letter)==NULL)
{
Node* nod=new Node;
rad->set_next_letter(letter,nod);
}
add_word(rad->get_ptr_letter(letter),S,poz+1);
}
bool delete_word(Node* rad,const string& S,int poz)
{
if(poz==S.size()) rad->dec_occ();
else
{
if(delete_word(rad->get_ptr_letter(S[poz]),S,poz+1))
rad->set_next_letter(S[poz],NULL);
}
if(rad!=root && !rad->get_occ() && !rad->get_fii())
{
delete rad;
return 1;
}
return 0;
}
int occurences(Node* rad,const string& S,int poz)
{
if(rad==NULL)
return 0;
if(poz==S.size())
return rad->get_occ();
return occurences(rad->get_ptr_letter(S[poz]),S,poz+1);
}
int longest_prefix(Node* rad,const string& S,int poz)
{
//se termina cuvanul desi mai este ramura
//sau nu mai este ramura
if(poz==S.size() || rad->get_ptr_letter(S[poz])==NULL)
return 0;
return 1+longest_prefix(rad->get_ptr_letter(S[poz]),S,poz+1);
}
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int op;
string S;
root=new Node;
while( f>>op>>S)
{
if(op==0)
add_word(root,S,0);
else
if(op==1)
delete_word(root,S,0);
else
if(op==2)
g<<occurences(root,S,0)<<'\n';
else
g<<longest_prefix(root,S,0)<<'\n';
}
delete root;
return 0;
}