#include <bits/stdc++.h>
using namespace std;
const int N = 300005, B = 35;
int n;
char t[N];
struct AC {
  struct Trie {
    int ch[26], fail, c, c2;
  } A[N];
  int siz[B], root[N], top, cnt;
  string str[N];
  void build(int RT) {
    queue<int> q;
    q.push(RT);
    while (!q.empty()) {
      int x = q.front(), F, k;
      q.pop();
      for (int i = 0; i < 26; i++)
        if (A[x].ch[i]) {
          F = A[x].fail;
          k = A[x].ch[i];
          while (F && !A[F].ch[i]) F = A[F].fail;
          if (F)
            A[k].fail = A[F].ch[i];
          else
            A[k].fail = RT;
          q.push(k);
          A[k].c2 = A[A[k].fail].c2 + A[k].c;
        }
    }
  }
  int merge(int x, int y) {
    if (!x || !y) return x + y;
    A[x].c = A[x].c | A[y].c;
    for (int i = 0; i < 26; i++) A[x].ch[i] = merge(A[x].ch[i], A[y].ch[i]);
    return x;
  }
  void Add(string s) {
    root[++top] = ++cnt;
    int x = root[top], len = s.length(), k;
    for (int i = 0; i < len; i++) {
      k = s[i] - 'a';
      if (!A[x].ch[k]) A[x].ch[k] = ++cnt;
      x = A[x].ch[k];
    }
    A[x].c++;
    siz[top] = 1;
    build(root[top]);
    while (top && siz[top] == siz[top - 1]) {
      merge(root[top - 1], root[top]);
      build(root[top - 1]);
      siz[top - 1] *= 2;
      top--;
    }
  }
  int Ask(string s) {
    int len = s.length(), sum = 0;
    for (int i = 1; i <= top; i++) {
      int x = root[i], k;
      for (int j = 0; j < len; j++) {
        k = s[j] - 'a';
        while (x && !A[x].ch[k]) x = A[x].fail;
        if (x)
          x = A[x].ch[k];
        else
          x = root[i];
        sum += A[x].c2;
      }
    }
    return sum;
  }
} IN, OUT;
int main() {
  scanf("%d", &n);
  int tp;
  while (n--) {
    scanf("%d %s", &tp, t);
    if (tp == 1)
      IN.Add(t);
    else if (tp == 2)
      OUT.Add(t);
    else
      cout << IN.Ask(t) - OUT.Ask(t) << '\n' << flush;
  }
}
