#include <bits/stdc++.h>
using namespace std;
const int N = 3e5 + 5;
struct ACA {
  int pool[N], ptp;
  int stk[30], sz[N], rt[N], rtid, tp;
  int nxt[N][26], tran[N][26], fail[N], end[N], num[N], tot;
  inline int newnode() { return ++tot; }
  int merge(int x, int y) {
    if (!x || !y) return x | y;
    for (int i = 0; i < 26; i++) nxt[x][i] = merge(nxt[x][i], nxt[y][i]);
    end[x] += end[y];
    pool[++ptp] = y;
    return x;
  }
  void build(int p) {
    queue<int> q;
    for (int i = 0; i < 26; i++)
      if (nxt[p][i])
        fail[tran[p][i] = nxt[p][i]] = p, q.push(nxt[p][i]);
      else
        tran[p][i] = p;
    while (!q.empty()) {
      int k = q.front();
      q.pop();
      num[k] = end[k] + num[fail[k]];
      for (int i = 0; i < 26; i++) {
        if (nxt[k][i]) {
          fail[tran[k][i] = nxt[k][i]] = tran[fail[k]][i];
          q.push(tran[k][i]);
        } else
          tran[k][i] = tran[fail[k]][i];
      }
    }
  }
  void ins(char *s, int n, int v) {
    rt[++rtid] = newnode();
    sz[rtid] = 1;
    int p = rt[rtid];
    for (int i = 0; i < n; i++) {
      int k = s[i] - 'a';
      if (!nxt[p][k]) nxt[p][k] = newnode();
      p = nxt[p][k];
    }
    end[p] += v;
    while (tp && sz[stk[tp]] < 2 * sz[rtid])
      rt[rtid] = merge(rt[rtid], rt[stk[tp]]), sz[rtid] += sz[stk[tp]], --tp;
    build(rt[rtid]);
    stk[++tp] = rtid;
  }
  int qry(char *s, int n) {
    int ans = 0;
    for (int i = 1; i <= tp; i++) {
      int p = rt[stk[i]];
      for (int i = 0; i < n; i++) {
        p = tran[p][s[i] - 'a'];
        ans += num[p];
      }
    }
    return ans;
  }
} ac;
int main() {
  int m;
  scanf("%d", &m);
  for (int i = 1; i <= m; i++) {
    static char s[N];
    int op;
    scanf("%d%s", &op, s);
    if (op == 1)
      ac.ins(s, strlen(s), 1);
    else if (op == 2)
      ac.ins(s, strlen(s), -1);
    else
      printf("%d\n", ac.qry(s, strlen(s))), fflush(stdout);
  }
  return 0;
}
