#include <bits/stdc++.h>
using namespace std;
const int BUBEN = sqrt(600 * 1000);
struct node {
  node* go[26];
  node* dpgo[26];
  node* link;
  node* parent;
  int lst;
  int dp;
  int id;
  node() {
    for (int i = 0; i < 26; i++) {
      go[i] = NULL;
      dpgo[i] = NULL;
    }
    parent = NULL;
    lst = -1;
    id = -1;
    link = NULL;
    dp = -1;
  }
};
void add(node* v, const string& s, int id) {
  for (int i = 0; i < (int)s.length(); i++) {
    int x = s[i] - 'a';
    if (v->go[x] == NULL) v->go[x] = new node();
    v->go[x]->parent = v;
    v->go[x]->lst = x;
    v = v->go[x];
  }
  v->id = id;
}
void del(node* v, const string& s) {
  for (int i = 0; i < (int)s.length(); i++) {
    int x = s[i] - 'a';
    v = v->go[x];
  }
  v->id = -1;
}
int getId(node* v, const string& s) {
  for (int i = 0; i < (int)s.length(); i++) {
    int x = s[i] - 'a';
    v = v->go[x];
  }
  return v->id;
}
const int MAXN = 300 * 1000 + 7;
char buf[MAXN];
string getString() {
  scanf("%s", buf);
  return string(buf);
}
string strs[MAXN];
bool alive[MAXN];
int strCnt = 0;
node* ahoRoot = new node();
void dfsClear(node* v) {
  if (v == NULL) return;
  for (int i = 0; i < 26; i++) {
    v->dpgo[i] = NULL;
  }
  v->link = NULL;
  v->dp = -1;
  for (int i = 0; i < 26; i++) {
    dfsClear(v->go[i]);
  }
}
node* go(node* v, int x);
node* getLink(node* v) {
  if (v->link != NULL) return v->link;
  if (v == ahoRoot || v->parent == ahoRoot) {
    v->link = ahoRoot;
  } else {
    v->link = go(getLink(v->parent), v->lst);
  }
  return v->link;
}
node* go(node* v, int x) {
  if (v->dpgo[x] != NULL) return v->dpgo[x];
  if (v->go[x] != NULL) {
    v->dpgo[x] = v->go[x];
  } else if (v == ahoRoot) {
    v->dpgo[x] = v;
  } else {
    v->dpgo[x] = go(getLink(v), x);
  }
  return v->dpgo[x];
}
int calcDp(node* v) {
  if (v->dp != -1) return v->dp;
  if (v == ahoRoot) {
    v->dp = 0;
    return 0;
  } else {
    v->dp = 0;
    if (v->id == 2) {
      v->dp = 1;
    }
    v->dp += calcDp(getLink(v));
  }
  return v->dp;
}
int main() {
  int n;
  scanf("%d\n", &n);
  for (int i = 1; i <= n; i++) {
    int type;
    scanf("%d ", &type);
    if (type == 1) {
      strCnt++;
      strs[strCnt] = getString();
      if ((int)strs[strCnt].length() > BUBEN) {
        dfsClear(ahoRoot);
        add(ahoRoot, strs[strCnt], 2);
      } else {
        add(ahoRoot, strs[strCnt], 1);
      }
    } else if (type == 2) {
      string cur = getString();
      del(ahoRoot, cur);
      if ((int)cur.length() > BUBEN) {
        dfsClear(ahoRoot);
      }
    } else if (type == 3) {
      string s = getString();
      long long res = 0;
      for (int i = 0; i < (int)s.length(); i++) {
        node* v = ahoRoot;
        for (int j = i; j < min((int)s.length(), i + BUBEN); j++) {
          v = v->go[s[j] - 'a'];
          if (v == NULL) break;
          if (v->id != -1) {
            res++;
          }
        }
      }
      node* v = ahoRoot;
      for (int i = 0; i < (int)s.length(); i++) {
        v = go(v, s[i] - 'a');
        res += calcDp(v);
      }
      printf("%lld\n", res);
      fflush(stdout);
    }
  }
}
