#include <bits/stdc++.h>
using namespace std;
ifstream in("trie.in");
ofstream out("trie.out");
struct thing{
int pre = 0, entire = 0;
} A;
void Add_Word_To_Tree(int node, int p, string word, vector<vector<int>> &Vec, vector<vector<char>> &Cost, vector<thing> &Appear)
{
Appear[node].pre++;
if (word.length() == 0)
{
Appear[node].entire++;
return;
}
for (int i = 0; i < Vec[node].size(); i++)
{
if (Vec[node][i] == p)
continue;
if (Cost[node][i] == word[0])
{
word.erase(word.begin());
Add_Word_To_Tree(Vec[node][i], node, word, Vec, Cost, Appear);
return;
}
}
Vec[node].push_back(Vec.size());
Vec.push_back(vector<int> (1, node));
Cost[node].push_back(word[0]);
Cost.push_back(vector<char> (1, word[0]));
Appear.push_back(A);
word.erase(word.begin());
Add_Word_To_Tree(Vec.size() - 1, node, word, Vec, Cost, Appear);
}
void DeleteWord(int node, int p, string word, vector<vector<int>> &Vec, vector<vector<char>> &Cost, vector<thing> &Appear)
{
Appear[node].pre = max(0, Appear[node].pre - 1);
if (word.length() == 0)
{
Appear[node].entire = max(0, Appear[node].entire - 1);
return;
}
for (int i = 0; i < Vec[node].size(); i++)
{
if (Vec[node][i] == p)
continue;
if (word[0] == Cost[node][i])
{
word.erase(word.begin());
DeleteWord(Vec[node][i], node, word, Vec, Cost, Appear);
return;
}
}
}
void Appearances(int node, int p, string word, vector<vector<int>> &Vec, vector<vector<char>> &Cost, vector<thing> &Appear)
{
if (word.length() == 0)
{
out<< Appear[node].entire << "\n";
return;
}
for (int i = 0; i < Vec[node].size(); i++)
{
if (Vec[node][i] == p)
continue;
if (word[0] == Cost[node][i])
{
word.erase(word.begin());
Appearances(Vec[node][i], node, word, Vec, Cost, Appear);
return;
}
}
out<< 0 << "\n";
}
void PrefixAppear(int node, int p, string word, vector<vector<int>> &Vec, vector<vector<char>> &Cost, vector<thing> &Appear)
{
int ans = 0;
int Sum = Appear[node].pre;
while (word.length() > 0 && Sum > 0)
{
bool Found = false;
for (int i = 0; i < Vec[node].size(); i++)
{
if (Vec[node][i] == p)
continue;
if (word[0] == Cost[node][i])
{
word.erase(word.begin());
Found = true;
p = node;
node = Vec[node][i];
Sum = Appear[node].pre;
if (Sum != 0)
ans++;
break;
}
}
if (!Found)
break;
}
out<< ans << "\n";
}
int main()
{
vector<vector<int>> Vec(1);
vector<vector<char>> Cost(1);
vector<thing> Appear(1, A);
int Type;
string Word;
while (in>> Type)
{
in>> Word;
switch (Type)
{
case 0: { Add_Word_To_Tree(0, -1, Word, Vec, Cost, Appear); break; }
case 1: { DeleteWord(0, -1, Word, Vec, Cost, Appear); break; }
case 2: { Appearances(0, -1, Word, Vec, Cost, Appear); break; }
case 3: { PrefixAppear(0, -1, Word, Vec, Cost, Appear); break; }
}
}
return 0;
}