#include <bits/stdc++.h>
using namespace std;
const int maxn = 3e5 + 7;
int m, t, trie[maxn][26], ch[maxn][26], tp[2], root[2][maxn], top, num[maxn],
    sz[2][maxn], fail[maxn], tot[maxn];
inline int merge(int x, int y) {
  if (!x || !y) return x | y;
  num[x] += num[y];
  for (register int i = 0; i < 26; i++)
    trie[x][i] = merge(trie[x][i], trie[y][i]);
  return x;
}
inline void build(int x) {
  queue<int> Q;
  for (register int i = 0; i < 26; i++)
    if (trie[x][i])
      fail[ch[x][i] = trie[x][i]] = x, Q.push(ch[x][i]);
    else
      ch[x][i] = x;
  while (!Q.empty()) {
    int now = Q.front();
    Q.pop();
    for (register int i = 0; i < 26; i++)
      if (ch[now][i] = trie[now][i])
        fail[ch[now][i]] = ch[fail[now]][i], Q.push(ch[now][i]);
      else
        ch[now][i] = ch[fail[now]][i];
    tot[now] = tot[fail[now]] + num[now];
  }
}
inline void insert(int o, char* s) {
  int u = root[o][++tp[o]] = ++top;
  for (register int i = 0; s[i]; i++)
    if (trie[u][s[i] - 'a'])
      u = trie[u][s[i] - 'a'];
    else
      u = trie[u][s[i] - 'a'] = ++top;
  num[u]++;
  sz[o][tp[o]] = 1;
  while (sz[o][tp[o]] == sz[o][tp[o] - 1])
    tp[o]--, sz[o][tp[o]] += sz[o][tp[o] + 1],
        merge(root[o][tp[o]], root[o][tp[o] + 1]);
  build(root[o][tp[o]]);
  return;
}
inline int query(int o, char* s) {
  int ans = 0;
  for (register int i = 1; i <= tp[o]; i++) {
    int u = root[o][i];
    for (register int j = 0; s[j]; j++) u = ch[u][s[j] - 'a'], ans += tot[u];
  }
  return ans;
}
char s[maxn];
int main() {
  scanf("%d", &m);
  while (m--) {
    scanf("%d%s", &t, &s);
    if (t == 3)
      printf("%d\n", query(0, s) - query(1, s));
    else
      insert(t - 1, s);
    fflush(stdout);
  }
  return 0;
}
