// Template v2
#define pb push_back
#define mp make_pair
#define first x
#define second y
#define l(x) x<<1
#define r(x) x<<1 | 1
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef long double LD;
typedef vector<int> VI;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
typedef pair<double, double> PKK;
// primes less than 100
const int PRIM[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97};
const int CMAX = 350;
const int MOD = 1000000007;
const int NMAX = 1005;
const short INF16 = 32000;
const int INF = int(1e9);
const LL INF64 = LL(1e18);
const LD EPS = 1e-9, PI = acos(-1.0);
struct Trie{
int a, b;
Trie* next[26];
Trie()
{
a=0; b=0;
memset(next, 0, sizeof(0));
}
};
Trie * R = new Trie;
int t;
string c;
void insert(Trie* node = R, int i=0)
{
if(i==c.size())
{
node->b++;
return;
}
if(node->next[c[i]-'a'] == NULL)
{
node->next[c[i]-'a']=new Trie;
node->a++;
}
insert(node->next[c[i]-'a'], i+1);
}
bool pop(Trie* node = R, int i=0)
{
if(i==c.size())
node->b--;
else
if(pop(node->next[c[i]-'a'], i+1))
{
node->next[c[i]-'a']=NULL;
node->a--;
}
if(node->b == 0 && node->a == 0 && node!=R)
{
delete node;
return true;
}
return false;
}
int search(Trie* node = R, int i = 0)
{
if(i==c.size())
return node->b;
if(node->next[c[i]-'a'])
return search(node->next[c[i]-'a'], i+1);
return 0;
}
int prefix(Trie* node = R, int i = 0)
{
if(i==c.size() || node->next[c[i]-'a']==NULL)
return i;
return prefix(node->next[c[i]-'a'], i+1);
}
void read()
{
while(cin>>t>>c)
{
if(t==0)
insert();
if(t==1)
pop();
if(t==2)
cout<<search()<<"\n";
if(t==3)
cout<<prefix()<<"\n";
}
}
int main() {
cin.tie(0);
ios_base::sync_with_stdio(0);
cout << setprecision(16) << fixed;
assert(freopen("trie.in", "rt", stdin));
assert(freopen("trie.out", "wt", stdout));
read();
return 0;
}