#include <bits/stdc++.h>
using namespace std;
const double PI = acos(-1);
template <class T>
T sqr(T x) {
  return x * x;
}
template <class T>
T alex(T x) {
  return (x > 0) ? x : -x;
}
template <class T>
void read(T& x) {
  x = 0;
  T f = 1;
  char ch = getchar();
  while ((ch < 48 || ch > 57) && ch != 45) ch = getchar();
  if (ch == 45) f = -1, ch = getchar();
  while (ch >= 48 && ch <= 57) x = x * 10 + ch - 48, ch = getchar();
  x *= f;
}
int n;
char s[300005];
struct Tree {
  int que[20];
  vector<char> ss[300005];
  int cnt;
  struct AC {
    struct Node {
      int son[26];
      Node() {}
    };
    vector<Node> son;
    vector<int> fail, cnt;
    int rot, len;
    Node Null;
    void init() {
      rot = len = 1;
      son.clear();
      son.push_back(Null);
      son.push_back(Null);
      fail.resize(2);
      cnt.resize(2);
      fail[0] = fail[1] = cnt[0] = cnt[1] = 0;
    }
    int Newnode() {
      len++;
      son.push_back(Null), fail.push_back(0), cnt.push_back(0);
      return len;
    }
    void insert(vector<char> s) {
      int now = rot;
      for (int i = (0); i < (s.size()); i++) {
        if (son[now].son[s[i] - 'a'])
          now = son[now].son[s[i] - 'a'];
        else {
          int p = Newnode();
          son[now].son[s[i] - 'a'] = p;
          now = p;
        }
      }
      cnt[now]++;
    }
    int que[300005];
    void work() {
      int head = 0, tail = 0;
      for (int i = (0); i <= (25); i++)
        if (son[rot].son[i])
          fail[que[++tail] = son[rot].son[i]] = rot;
        else
          son[rot].son[i] = rot;
      while (head != tail) {
        head++;
        for (int i = (0); i <= (25); i++)
          if (son[que[head]].son[i]) {
            que[++tail] = son[que[head]].son[i];
            fail[son[que[head]].son[i]] = son[fail[que[head]]].son[i];
          } else
            son[que[head]].son[i] = son[fail[que[head]]].son[i];
      }
      for (int i = (1); i <= (len - 1); i++) cnt[que[i]] += cnt[fail[que[i]]];
    }
    long long query(char* s) {
      int len = strlen(s + 1);
      int now = rot;
      long long res = 0;
      for (int i = (1); i <= (len); i++)
        now = son[now].son[s[i] - 'a'], res += cnt[now];
      return res;
    }
  } AC[20];
  void insert(char* s) {
    que[++que[0]] = 1;
    cnt++;
    int len = strlen(s + 1);
    for (int i = (1); i <= (len); i++) ss[cnt].push_back(s[i]);
    while (que[0] > 1 && que[que[0]] == que[que[0] - 1])
      que[que[0] - 1] <<= 1, que[0]--;
    AC[que[0]].init();
    for (int i = (cnt - que[que[0]] + 1); i <= (cnt); i++)
      AC[que[0]].insert(ss[i]);
    AC[que[0]].work();
  }
  long long query(char* s) {
    long long res = 0;
    for (int i = (1); i <= (que[0]); i++) res += AC[i].query(s);
    return res;
  }
} s1, s2;
int main() {
  read(n);
  for (int i = (1); i <= (n); i++) {
    int op;
    read(op);
    scanf("%s", s + 1);
    if (op == 1)
      s1.insert(s);
    else if (op == 2)
      s2.insert(s);
    else
      printf("%lld\n", s1.query(s) - s2.query(s)), fflush(stdout);
  }
  return 0;
}
