#include <iostream>
#include <cstring>
#include <fstream>
#define VMAX 105
#define INF 2000000000
using namespace std;
ifstream fin ("trie.in");
ofstream fout ("trie.out");
const int mod = 10;
int numere[2][VMAX];
struct nod {
int cnt, pre;
nod * next[26];
};
void initializeaza_nod(nod& a)
{
a.cnt=0;
a.pre=0;
for(int i=0;i<26;i++)
a.next[i]=NULL;
}
void insereaza(nod * trie, string w, int pos) {
if(pos == w.size()) {
trie->cnt++;
trie->pre++;
} else {
if(trie->next[w[pos] - 'a'] == NULL)
{
trie->next[w[pos] - 'a'] = new nod();
initializeaza_nod(*(trie->next[w[pos] - 'a']));
}
insereaza(trie->next[w[pos] - 'a'], w, pos + 1);
trie->pre++;
}
}
void sterge(nod * trie, string w, int pos)
{
if(pos==w.size())
{
trie->cnt--;
trie->pre--;
}
else
{
sterge(trie->next[w[pos]-'a'],w,pos+1);
trie->pre--;
}
}
int sol_2(nod * trie, string w, int pos)
{
if(pos==w.size())
return trie->cnt;
else if(trie->next[w[pos] - 'a'] == NULL)
return 0;
else
{
return sol_2(trie->next[w[pos] - 'a'] , w , pos+1);
}
}
int sol_3(nod * trie, string w, int pos)
{
if(trie->pre==0)
return pos-1;
else if(trie->next[w[pos] - 'a'] == NULL)
return pos;
else
{
return sol_3(trie->next[w[pos] - 'a'], w, pos+1);
}
}
int cauta(nod* rad, string a) {
nod* p = rad;
for(char c : a) {
int index = c - 'a';
if(!p->next[index]) return false;
p = p->next[index];
}
return p->cnt;
}
int cauta_prefix2(nod* rad, string a) {
nod * p = rad;
int cnt = 0;
for(int i = 0;i<a.length();++i) {
int index = a[i] - 'a';
if(!p->next[index]) return cnt;
if(p->next[index]->pre > 0) cnt = i + 1;
p = p->next[index];
}
return cnt;
}
string s;
int main()
{
ios_base::sync_with_stdio(0);
long long int n,m,i,j,k,t,q,nr,ult_nr,pow10_,a,b,minim,maxim,suma,lga,lgb;
nod tree;
nod* tre=&tree;
initializeaza_nod(tree);
while(fin>>n>>s)
{
if(n==0)
insereaza(tre,s,0);
else if(n==1)
sterge(tre,s,0);
else if(n==2)
{
fout<<cauta(tre,s)<<'\n';
}
else
{
fout<<cauta_prefix2(tre,s)<<'\n';
}
}
return 0;
}