#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;
struct AcAutomaton {
  int ch[N][26], fail[N], T[21], idx, ed, endp[N], path[N];
  vector<string> sta[21];
  inline void update(int id) {
    T[id] = (++idx);
    for (string s : sta[id]) {
      int pos = T[id], to;
      for (char c : s) {
        to = c - 'a';
        if (!ch[pos][to]) ch[pos][to] = (++idx);
        pos = ch[pos][to];
      }
      endp[pos]++;
    }
    queue<int> q;
    for (int i = (0); i <= (25); i++)
      if (ch[T[id]][i])
        q.push(ch[T[id]][i]), fail[ch[T[id]][i]] = T[id];
      else
        ch[T[id]][i] = T[id];
    while (!q.empty()) {
      int u = q.front();
      q.pop();
      path[u] = path[fail[u]] + endp[u];
      for (int i = (0); i <= (25); i++) {
        if (!ch[u][i])
          ch[u][i] = ch[fail[u]][i];
        else
          fail[ch[u][i]] = ch[fail[u]][i], q.push(ch[u][i]);
      }
    }
  }
  inline void merge() {
    for (string s : sta[ed]) sta[ed - 1].push_back(s);
    sta[ed].clear();
    ed--;
  }
  inline void insert(string s) {
    sta[ed + 1].push_back(s);
    ed++;
    while (ed > 1 && sta[ed].size() == sta[ed - 1].size()) merge();
    update(ed);
  }
  inline long long query(string s) {
    long long ans = 0;
    int pos, to;
    for (int i = (1); i <= (ed); i++) {
      pos = T[i];
      for (char c : s) {
        to = c - 'a';
        pos = ch[pos][to];
        ans += path[pos];
      }
    }
    return ans;
  }
} ad, de;
int n, opt;
string s;
inline void solve() {
  scanf("%d", &n);
  for (int i = (1); i <= (n); i++) {
    scanf("%d", &opt);
    cin >> s;
    if (opt == 1) ad.insert(s);
    if (opt == 2) de.insert(s);
    if (opt == 3) printf("%lld\n", ad.query(s) - de.query(s));
    fflush(stdout);
  }
}
int main() { solve(); }
