#include <bits/stdc++.h>
using namespace std;
constexpr char nl = '\n';
template <class array, class B>
array&& mini(array&& a, B&& b) {
  if (b < a) a = b;
  return a;
}
template <class array, class B>
array&& maxi(array&& a, B&& b) {
  if (b > a) a = b;
  return a;
}
int first_bit(int x) { return x == 0 ? 0 : sizeof(x) * 8 - __builtin_clz(x); }
int ceil2(int x) { return x < 2 ? x : 1 << first_bit(x - 1); }
constexpr int inf = 0x3f3f3f3f;
constexpr long long inf_l = 0x3f3f3f3f3f3f3f3f;
struct Debug;
template <class T>
auto _is_debug_func(T&& x)
    -> decltype(x(declval<add_lvalue_reference<Debug>::type>()), true_type{});
false_type _is_debug_func(...);
template <class T>
struct is_debug_func : decltype(_is_debug_func(declval<T>())) {};
;
template <class T>
auto _is_func(T&& x) -> decltype(x(), true_type{});
false_type _is_func(...);
template <class T>
struct is_func : decltype(_is_func(declval<T>())) {};
template <class T>
auto _is_string(T&& x) -> decltype(string(x), true_type{});
false_type _is_string(...);
template <class T>
struct is_string : decltype(_is_string(declval<T>())) {};
template <class T>
auto _is_ptr(T&& x)
    -> decltype(*x, typename enable_if<is_string<T>() == false, int>::type(),
                true_type{});
false_type _is_ptr(...);
template <class T>
struct is_ptr : decltype(_is_ptr(declval<T>())) {};
;
template <class T>
auto _is_container(T&& x)
    -> decltype(x.begin(),
                typename enable_if<is_string<T>() == false, int>::type(),
                true_type{});
false_type _is_container(...);
template <class T>
struct is_container : decltype(_is_container(declval<T>())) {};
template <class Iter>
struct Off {
  Iter _a, _b;
};
template <class T>
auto O(T&& x)
    -> decltype(typename enable_if<is_container<T>() == true, int>::type(),
                Off<decltype(x.begin())>()) {
  return {x.begin(), x.end()};
}
template <class T>
auto O(T&& x)
    -> decltype(typename enable_if<is_container<T>() == false, int>::type(),
                x) {
  return x;
}
struct Debug {
  Debug() { cerr << boolalpha << fixed << setprecision(0); }
  ~Debug() { cerr << nl; }
  Debug& operator()(int x = 1) {
    for (auto _ = (0), ___ = ((x)-1); _ <= ___; ++_) *this << "  ";
    return *this;
  }
  template <class T>
  auto operator<<(T&& x)
      -> decltype(cerr << x,
                  typename enable_if<
                      is_func<T>() == false && is_ptr<T>() == false &&
                          is_integral<typename remove_reference<T>::type>() ==
                              true,
                      int>::type(),
                  *this) {
    using L = long long;
    if (abs(int(x)) == inf || abs(L(x)) == inf_l)
      cerr << ((int(x) == inf || L(x) == inf_l)     ? "+∞"
               : (int(x) == -inf || L(x) == -inf_l) ? "-∞"
                                                    : "?");
    else
      cerr << x;
    return *this;
  }
  template <class T>
  auto operator<<(T&& x)
      -> decltype(cerr << x,
                  typename enable_if<
                      is_func<T>() == false && is_ptr<T>() == false &&
                          is_integral<typename remove_reference<T>::type>() ==
                              false,
                      int>::type(),
                  *this) {
    cerr << x;
    return *this;
  }
  template <class T>
  auto operator<<(T&& x) -> decltype(x.first, *this) {
    return *this << "(" << O(x.first) << ", " << O(x.second) << ")";
  }
  template <class T>
  auto operator<<(T&& x)
      -> decltype(typename enable_if<is_container<T>() == true, int>::type(),
                  *this) {
    *this << "{\n";
    for (auto a = x.begin(); a != x.end(); ++a)
      *this << "  " << distance(x.begin(), a) << ": " << O(*a) << '\n';
    return *this << "}";
  }
  template <class T>
  auto operator<<(T&& x) -> decltype(x._a, *this) {
    *this << "{";
    for (auto a = x._a, b = x._b; a != b; ++a)
      *this << O(*a) << (next(a) == b ? "" : ", ");
    return *this << "}";
  }
  template <class T>
  auto operator<<(T&& x)
      -> decltype(typename enable_if<is_func<T>() == true, int>::type(),
                  *this) {
    x();
    return *this;
  }
  template <class T>
  auto operator<<(T&& x)
      -> decltype(typename enable_if<is_debug_func<T>() == true, int>::type(),
                  *this) {
    x(*this);
    return *this;
  }
  template <class T>
  auto operator<<(T&& x)
      -> decltype(typename enable_if<is_ptr<T>() == true &&
                                         is_func<T>() == false &&
                                         is_debug_func<T>() == false,
                                     int>::type(),
                  *this) {
    return *this << *x;
  }
};
struct DebugOff {
  template <class T>
  DebugOff& operator<<(T&&) {
    return *this;
  }
  DebugOff& operator()(int = 0) { return *this; }
};
using VI = vector<int>;
using VVI = vector<VI>;
using L = long long;
using VL = vector<L>;
using VB = vector<bool>;
using II = pair<int, int>;
using VII = vector<II>;
using VVII = vector<VII>;
int main() {
  ios_base::sync_with_stdio(0);
  cin.tie(0);
  int n, q;
  cin >> n >> q;
  string s;
  cin >> s;
  int alfa = 26;
  vector<vector<int>> nxt(n + 1, vector<int>(alfa, n + 1));
  vector<int> last(alfa, n + 1);
  for (auto i = ((n)-1), i__ = (0); i >= i__; --i) {
    nxt[i + 1] = last;
    last[int(s[i] - 'a')] = i + 1;
  }
  nxt[0] = last;
  DebugOff() << "nxt"
                ": "
             << nxt << "   ";
  auto znak = [&](char c) { return int(c - 'a'); };
  int mxSize = 253;
  vector<string> in(3);
  vector<vector<vector<int>>> dp(
      mxSize, vector<vector<int>>(mxSize, vector<int>(mxSize, n + 1)));
  dp[0][0][0] = 0;
  auto calcDP = [&](int i, int j, int k) {
    if (i == 0 && j == 0 && k == 0) {
      dp[i][j][k] = 0;
      return;
    }
    dp[i][j][k] = n + 1;
    if (i != 0 && dp[i - 1][j][k] != n + 1)
      dp[i][j][k] = min(dp[i][j][k], nxt[dp[i - 1][j][k]][znak(in[0][i - 1])]);
    if (j != 0 && dp[i][j - 1][k] != n + 1)
      dp[i][j][k] = min(dp[i][j][k], nxt[dp[i][j - 1][k]][znak(in[1][j - 1])]);
    if (k != 0 && dp[i][j][k - 1] != n + 1)
      dp[i][j][k] = min(dp[i][j][k], nxt[dp[i][j][k - 1]][znak(in[2][k - 1])]);
  };
  while (q-- > 0) {
    char c;
    int id;
    cin >> c >> id;
    --id;
    if (c == '+') {
      char xx;
      cin >> xx;
      in[id] += xx;
      int x = ((int)in[0].size()), y = ((int)in[1].size()),
          z = ((int)in[2].size());
      if (id == 0)
        for (auto j = (0), j__ = (y); j <= j__; ++j)
          for (auto k = (0), k__ = (z); k <= k__; ++k) calcDP(x, j, k);
      else if (id == 1)
        for (auto i = (0), i__ = (x); i <= i__; ++i)
          for (auto k = (0), k__ = (z); k <= k__; ++k) calcDP(i, y, k);
      else if (id == 2)
        for (auto i = (0), i__ = (x); i <= i__; ++i)
          for (auto j = (0), j__ = (y); j <= j__; ++j) calcDP(i, j, z);
      DebugOff() << "dp"
                    ": "
                 << dp << "   ";
      cout << (dp[x][y][z] == n + 1 ? "NO" : "YES") << '\n';
    } else {
      in[id].pop_back();
      int x = ((int)in[0].size()), y = ((int)in[1].size()),
          z = ((int)in[2].size());
      cout << (dp[x][y][z] == n + 1 ? "NO" : "YES") << '\n';
    }
  }
}
