#include <bits/stdc++.h>
using namespace std;
struct node {
  int cnt, fcnt;
  node *ch[26], *fail;
  node() {
    cnt = fcnt = 0;
    fail = NULL;
    memset(ch, 0, sizeof ch);
  }
} pn[300010], *r[2], *trash[300010];
int n, siz, nT, h;
char s[300010];
queue<node *> Q;
node *newNode() {
  siz++;
  if (h) {
    *trash[--h] = node();
    return trash[h];
  } else
    return &pn[nT++];
}
void ins(int v) {
  node *p = r[1];
  for (int i = 0; s[i]; i++) {
    if (!p->ch[s[i] - 'a']) p->ch[s[i] - 'a'] = newNode();
    p = p->ch[s[i] - 'a'];
  }
  p->cnt += v;
}
void buildFail(node *r) {
  Q.push(r);
  node *p, *q;
  while (!Q.empty()) {
    p = Q.front();
    Q.pop();
    for (int i = 0; i < 26; i++) {
      if (!p->ch[i]) continue;
      q = p->fail;
      while (q && !q->ch[i]) q = q->fail;
      if (!q)
        p->ch[i]->fail = r;
      else
        p->ch[i]->fail = q->ch[i];
      p->ch[i]->fcnt = p->ch[i]->cnt + p->ch[i]->fail->fcnt;
      Q.push(p->ch[i]);
    }
  }
}
node *merge(node *a, node *b) {
  if (!a) return b;
  if (!b) return a;
  a->cnt += b->cnt;
  a->fail = NULL;
  trash[h++] = b;
  for (int i = 0; i < 26; i++) a->ch[i] = merge(a->ch[i], b->ch[i]);
  return a;
}
int go(node *r) {
  int ret = 0;
  node *p = r;
  for (int i = 0; s[i]; i++) {
    while (p && !p->ch[s[i] - 'a']) p = p->fail;
    if (!p)
      p = r;
    else
      p = p->ch[s[i] - 'a'];
    ret += p->fcnt;
  }
  return ret;
}
int main() {
  scanf("%d", &n);
  int op, B = sqrt(n);
  r[0] = &(pn[nT++] = node()), r[1] = newNode();
  for (int i = 0; i < n; i++) {
    scanf("%d%s", &op, s);
    if (op == 1)
      ins(1), buildFail(r[1]);
    else if (op == 2)
      ins(-1), buildFail(r[1]);
    if (op <= 2 && siz > B)
      r[0] = merge(r[0], r[1]), buildFail(r[0]), siz = 0, r[1] = newNode();
    if (op == 3) printf("%d\n", go(r[0]) + go(r[1])), fflush(stdout);
  }
  return 0;
}
