#include <bits/stdc++.h>
using namespace std;
struct Edge {
  int from, to;
  char letter;
  Edge(int f, int t, char e) {
    from = f;
    to = t;
    letter = e;
  }
  Edge() {}
};
struct Node {
  int id, fail;
  string word;
  int numOfWords = 0;
  vector<Edge> edges;
  Node(int ID) {
    id = ID;
    fail = 1;
    edges = vector<Edge>(0);
    word = "";
    numOfWords = 0;
  }
  Node() {}
};
struct Aho {
  vector<string> words;
  vector<Node> nodes;
  void addEdge(int u, char edge) {
    if (Goto(u, edge) > 1) return;
    Node newNode(nodes.size() + 1);
    Edge e(u, newNode.id, edge);
    nodes[u - 1].edges.push_back(e);
    nodes.push_back(newNode);
  }
  void makeTrie() {
    for (int i = 0; i < words.size(); i++) {
      int u = 1;
      for (int j = 0; j < words[i].size(); j++) {
        addEdge(u, words[i][j]);
        u = Goto(u, words[i][j]);
      }
      nodes[u - 1].word = words[i];
      nodes[u - 1].numOfWords = 1;
    }
  }
  int Goto(int u, char edge) {
    for (int i = 0; i < nodes[u - 1].edges.size(); i++) {
      if (nodes[u - 1].edges[i].letter == edge) return nodes[u - 1].edges[i].to;
    }
    if (u == 1) return u;
    return -1;
  }
  void bfs() {
    queue<int> Q;
    Q.push(1);
    while (!Q.empty()) {
      int u = Q.front();
      Q.pop();
      for (int i = 0; i < nodes[u - 1].edges.size(); i++) {
        int s = nodes[u - 1].edges[i].to;
        int v = nodes[u - 1].fail;
        while (Goto(v, nodes[u - 1].edges[i].letter) == -1)
          v = nodes[v - 1].fail;
        nodes[s - 1].fail = Goto(v, nodes[u - 1].edges[i].letter);
        if (nodes[s - 1].fail == s) nodes[s - 1].fail = 1;
        nodes[s - 1].numOfWords += nodes[nodes[s - 1].fail - 1].numOfWords;
        Q.push(s);
      }
    }
  }
  long long search(string s) {
    int u = 1;
    long long ans = 0;
    for (int i = 0; i < s.size(); i++) {
      while (Goto(u, s[i]) == -1) u = nodes[u - 1].fail;
      u = Goto(u, s[i]);
      ans += nodes[u - 1].numOfWords;
    }
    return ans;
  }
  Aho(vector<string> strs) {
    nodes.push_back(Node(1));
    words = vector<string>(0);
    for (int i = 0; i < strs.size(); i++) words.push_back(strs[i]);
    makeTrie();
    bfs();
  }
};
struct AhoBlocks {
  list<Aho> AhoTrees;
  void insert(string str) {
    Aho newTree(vector<string>(1, str));
    AhoTrees.push_front(newTree);
    list<Aho>::iterator it1 = AhoTrees.begin(), it2 = it1++;
    while (AhoTrees.size() > 1 && it1->words.size() == it2->words.size()) {
      vector<string> words(it1->words);
      words.insert(words.end(), it2->words.begin(), it2->words.end());
      AhoTrees.pop_front();
      AhoTrees.pop_front();
      AhoTrees.push_front(Aho(words));
      it1 = AhoTrees.begin(), it2 = it1++;
    }
  }
  long long search(string str) {
    long long ans = 0;
    for (list<Aho>::iterator it = AhoTrees.begin(); it != AhoTrees.end();
         ++it) {
      ans += it->search(str);
    }
    return ans;
  }
};
int main() {
  int M;
  cin >> M;
  AhoBlocks all, deleted;
  for (int i = 0; i < M; i++) {
    int t;
    string str;
    cin >> t >> str;
    if (t == 3) {
      cout << all.search(str) - deleted.search(str) << endl;
      continue;
    }
    if (t == 2) {
      deleted.insert(str);
      continue;
    }
    all.insert(str);
  }
  int de;
  cin >> de;
}
