#include <bits/stdc++.h>
using namespace std;
struct node {
  int val, lev;
  char ch;
  node *next[26], *fail, *pa;
  node *output;
  vector<int> pat;
  node() {
    lev = val = 0;
    pa = fail = NULL;
    for (int i = 0; i <= 25; i++) next[i] = NULL;
  }
};
node *Root[41];
vector<string> stringGroup[41];
string pattern, text;
int heads[41], id[41];
int ID(char ch) {
  int v;
  if (ch < 'a')
    v = ch - 'A';
  else
    v = ch - 'a';
  return v;
}
void in(string str, int RootId) {
  node *s = Root[RootId];
  int n = str.size();
  for (int i = 0; i <= n - 1; i++) {
    int x = ID(str[i]);
    if (s->next[x] == NULL) {
      s->next[x] = new node();
      s->next[x]->ch = str[i];
      s->next[x]->pa = s;
    }
    s = s->next[x];
  }
  s->val = s->val + 1;
  return;
}
queue<node *> que;
void outputLink(node *go, node *p) { p->val += go->val; }
void bfs(node *p, int RootId) {
  que.push(p);
  while (!que.empty()) {
    p = que.front();
    que.pop();
    int C = ID(p->ch);
    ;
    if (p->pa == Root[RootId]) {
      p->fail = Root[RootId];
      p->output = Root[RootId];
    } else {
      node *s = p->pa->fail;
      while (true) {
        if (s->next[C] != NULL) {
          p->fail = s->next[C];
          outputLink(s->next[C], p);
          break;
        } else if (Root[RootId] == s) {
          p->fail = s;
          p->output = Root[RootId];
          break;
        }
        s = s->fail;
      }
    }
    for (int i = 0; i <= 25; i++) {
      if (p->next[i] != NULL) {
        p->next[i]->lev = p->lev + 1;
        que.push(p->next[i]);
      }
    }
  }
}
int readText(string text, int RootId) {
  int p = 0, n = text.size(), x, ret = 0;
  node *s = Root[RootId];
  while (p < n) {
    int x = ID(text[p]);
    if (s->next[x] != NULL) {
      s = s->next[x];
      ret += s->val;
      p++;
    } else if (s == Root[RootId])
      p++;
    else
      s = s->fail;
  }
  return ret;
}
void make_aho(int RootId) {
  Root[RootId] = new node();
  Root[RootId]->fail = Root[RootId];
  Root[RootId]->pa = Root[RootId];
  Root[RootId]->val = 0;
  Root[RootId]->output = Root[RootId];
  int q, n;
  for (auto x : stringGroup[RootId]) {
    in(x, RootId);
  }
  bfs(Root[RootId], RootId);
}
int readAho(string text, int RootId) { return readText(text, RootId); }
void sortID(int l, int r) {
  for (int i = l; i <= r; i++) id[i] = i;
  sort(id + l, id + (r + 1), [](int a, int b) { return heads[a] < heads[b]; });
  return;
}
void mergeId(int a, int b) {
  for (auto x : stringGroup[a]) {
    stringGroup[b].push_back(x);
  }
  heads[b] += heads[a];
  heads[a] = 0;
  stringGroup[a].clear();
  make_aho(a);
  make_aho(b);
}
void addString(string str, int l, int r) {
  sortID(l, r);
  int G = id[l];
  stringGroup[G].push_back(pattern);
  heads[G]++;
  make_aho(G);
  int ok = 1;
  while (ok) {
    ok = 0;
    sortID(l, r);
    for (int i = l; i <= r; i++) {
      if (heads[id[i]] == heads[id[i + 1]] && heads[id[i]])
        mergeId(id[i], id[i + 1]), ok = 1;
    }
  }
}
int main() {
  ios::sync_with_stdio(false);
  for (int i = 0; i <= 40; i++) make_aho(i);
  int q, ty;
  cin >> q;
  for (int i = 1; i <= q; i++) {
    cin >> ty >> pattern;
    if (ty == 1)
      addString(pattern, 0, 19);
    else if (ty == 2)
      addString(pattern, 20, 39);
    else {
      int prin = 0;
      for (int i = 0; i <= 39; i++) {
        if (i <= 19)
          prin += readText(pattern, i);
        else
          prin -= readText(pattern, i);
      }
      cout << prin << endl;
    }
  }
  return 0;
}
