#include <bits/stdc++.h>
int32_t getSingleOccurences(std::string& pattern, std::string& str) {
  std::string full_pattern = pattern + "#" + str;
  int32_t* z_func = new int32_t[full_pattern.size()];
  z_func[0] = 0;
  int32_t left = 0, right = -1;
  for (int32_t i = 1; i < full_pattern.size(); i++) {
    z_func[i] = i <= right ? std::min(right - i + 1, z_func[i - left]) : 0;
    while (i + z_func[i] < full_pattern.size() &&
           full_pattern[z_func[i]] == full_pattern[i + z_func[i]])
      z_func[i]++;
    if (i + z_func[i] > right) {
      left = i;
      right = i + z_func[i] - 1;
    }
  }
  int32_t res = 0;
  for (int32_t i = pattern.size() + 1; i < full_pattern.size(); i++)
    res += (z_func[i] >= pattern.size() ? 1 : 0);
  return res;
}
struct TrieNode {
  int32_t go[26];
  int32_t suf_ref;
  int32_t supersuf;
  int32_t parent;
  char parent_char;
  int32_t value = 0;
  TrieNode() {
    for (int32_t i = 0; i < 26; i++) go[i] = -1;
  }
};
class AhoCorasick {
 private:
  std::vector<TrieNode> trie;

 public:
  AhoCorasick(std::vector<std::string>& strings) {
    trie.push_back({});
    for (int32_t i = 0; i < strings.size(); i++) {
      int32_t v = 0;
      for (int32_t j = 0; j < strings[i].size(); j++) {
        if (trie[v].go[strings[i][j] - 'a'] == -1) {
          trie[v].go[strings[i][j] - 'a'] = trie.size();
          trie.push_back({});
          trie[trie[v].go[strings[i][j] - 'a']].parent = v;
          trie[trie[v].go[strings[i][j] - 'a']].parent_char =
              strings[i][j] - 'a';
        }
        v = trie[v].go[strings[i][j] - 'a'];
      }
      trie[v].value++;
    }
    trie[0].parent = trie.size();
    trie.push_back({});
    trie[0].parent_char = 'a';
    for (int32_t i = 0; i < 26; i++) trie[trie.size() - 1].go[i] = 0;
    std::queue<int32_t> bfs_queue;
    bfs_queue.push(0);
    while (bfs_queue.size() > 0) {
      int32_t v = bfs_queue.front();
      bfs_queue.pop();
      if (v > 0)
        trie[v].suf_ref =
            trie[trie[trie[v].parent].suf_ref].go[trie[v].parent_char];
      else
        trie[v].suf_ref = trie.size() - 1;
      if (v == 0 || trie[v].suf_ref == 0)
        trie[v].supersuf = 0;
      else if (trie[trie[v].suf_ref].value == 0)
        trie[v].supersuf = trie[trie[v].suf_ref].supersuf;
      else
        trie[v].supersuf = trie[v].suf_ref;
      for (char ch = 'a'; ch <= 'z'; ch++)
        if (trie[v].go[ch - 'a'] != -1)
          bfs_queue.push(trie[v].go[ch - 'a']);
        else
          trie[v].go[ch - 'a'] = trie[trie[v].suf_ref].go[ch - 'a'];
    }
  }
  int32_t getNumOccurenciers(std::string& str) {
    int32_t res = 0;
    int32_t v = 0;
    for (int32_t i = 0; i < str.size(); i++) {
      v = trie[v].go[str[i] - 'a'];
      res += trie[v].value;
      int32_t cur = v;
      while (cur != 0) {
        cur = trie[cur].supersuf;
        res += trie[cur].value;
      }
    }
    return res;
  }
};
int main() {
  std::ios::sync_with_stdio(false);
  std::cin.tie(0);
  std::cout.tie(0);
  int32_t m;
  std::cin >> m;
  int32_t limit = std::ceil(std::sqrt(m));
  std::vector<std::string> pending_add, pending_delete;
  std::vector<AhoCorasick> fixed_add, fixed_delete;
  for (int32_t q = 0; q < m; q++) {
    int32_t type;
    std::string str;
    std::cin >> type >> str;
    if (type == 1) {
      pending_add.push_back(str);
      if (pending_add.size() == limit) {
        fixed_add.emplace_back(pending_add);
        pending_add.clear();
      }
    } else if (type == 2) {
      pending_delete.push_back(str);
      if (pending_delete.size() == limit) {
        fixed_delete.emplace_back(pending_delete);
        pending_delete.clear();
      }
    } else {
      int64_t res = 0;
      for (int32_t i = 0; i < pending_add.size(); i++)
        res += getSingleOccurences(pending_add[i], str);
      for (int32_t i = 0; i < fixed_add.size(); i++)
        res += fixed_add[i].getNumOccurenciers(str);
      for (int32_t i = 0; i < pending_delete.size(); i++)
        res -= getSingleOccurences(pending_delete[i], str);
      for (int32_t i = 0; i < fixed_delete.size(); i++)
        res -= fixed_delete[i].getNumOccurenciers(str);
      std::cout << res << std::endl;
    }
  }
  return 0;
}
