#include <bits/stdc++.h>
#define ld long double
#define endl "\n"
#define fastio ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define pb push_back
#define mp(a,b) make_pair(a,b)
#define ms(v,x) memset(v,x,sizeof(v))
#define all(v) v.begin(),v.end()
#define ff first
#define ss second
#define rep(i, a, b) for(int i = a; i < (b); ++i)
#define per(i, a, b) for(int i = b-1; i>=a ; i--)
#define trav(a, x) for(auto& a : x)
#define allin(a , x) for(auto a : x)
#define Unique(v) sort(all(v));v.erase(unique(all(v)),v.end());
#define sz(v) ((int)v.size())
//#define int long long  
using namespace std;
typedef vector<int> vi;
#define y1 abacaba
//#define left oooooopss
#define db(x) cerr << #x <<" == "<<x << endl;
#define db2(x,y) cerr<<#x <<" == "<<x<<", "<<#y<<" == "<<y<<endl;
#define db3(x,y,z) cerr << #x<<" == "<<x<<", "<<#y<<" == "<<y<<", "<<#z<<" == "<<z<<endl;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
std::mt19937 rng((int) std::chrono::steady_clock::now().time_since_epoch().count());
inline ll mod(ll n, ll m ){ ll ret = n%m; if(ret < 0) ret += m; return ret; }
ll gcd(ll a, ll b){return (b == 0LL ? a : gcd(b, a%b));}
ll exp(ll b,ll e,ll m){
  b%=m;
  ll ans = 1;
  for (; e; b = b * b % m, e /= 2)
      if (e & 1) ans = ans * b % m;
  return ans;
}


const int N = 200100;
// BENQ Dynacon
typedef array<int,3> arr;

map<int,int> mapa[N];
template <class T>
struct dcq{
  vector<vector<T>> st; int n;
  vi ans;
  vi ans2;
  dcq(int n ) : st(2*n , vector<T>()) , ans(n) , ans2(n),  n(n){}
  void upd(int x , int y , T q){ //evento Q em [X,Y] (eventos 0 index)
    for(x += n, y += n+1; x < y ; x/=2 , y/=2){
      if(x&1) st[x++].push_back(q);
      if(y&1) st[--y].push_back(q);
    }
    return;
  }
  int act = 0;
  int act2 = 0;

  void solve(int curr = 1){
    
    allin(w, st[curr]){
      // adiciona as coisas
      int a = w[0],b = w[1],c = w[2];
      if(mapa[b].count(a)){
        int ot = mapa[b][a];
        if(ot==c)act++;
        act2++;
      }
      mapa[a][b] = c;
    }
    if(curr >= n){
      // responde em ans[curr -n]
      ans[curr - n] = (act ? 1 : 0);
      ans2[curr - n] = (act2 ? 1 : 0);

    }
    else{
      solve(2*curr) ; solve(2*curr+1);
    }
    // da roll back
    allin(w, st[curr]){
      // adiciona as coisas
      int a = w[0],b = w[1],c = w[2];
      if(mapa[b].count(a)){
        int ot = mapa[b][a];
        if(ot==c)act--;
        act2--;
      }
      mapa[a].erase(b);
    }


    return ;
  } 
};

int need[N];
struct coisa{
  int l,r;
  arr a;
  coisa(){}
  coisa(int L,int R,arr A){
    l = L;
    r = R;
    a = A;
  }
};

int32_t main(){
  fastio;
  int n,m;
  cin >> n >> m;

  map<pii,pii> mp;

  vector<coisa> ev;
  rep(i,0,m){
    char op;
    cin >> op;
    if(op == '+'){
      int a,b;
      char ch;
      cin >> a >> b >> ch;
      int c = ch-'a';
      mp[pii(a,b)] = pii(i,c);
    }else if(op == '-'){
      int a,b;
      cin >> a >> b;
      int l = mp[pii(a,b)].ff;
      int c = mp[pii(a,b)].ss;
      ev.pb(coisa(l,i,arr({a,b,c})));
      mp.erase(pii(a,b));
    }else if(op == '?'){
      int k;
      cin >> k;
      need[i] = 1 + (k%2);
    }
  }
  for(auto AA : mp){
    auto it = AA.ss;
    ev.pb(coisa(it.ff,m,arr({AA.ff.ff,AA.ff.ss,it.ss})));
  }
  dcq<arr> D(m + 2);


  for(auto it : ev){
    D.upd(it.l,it.r,it.a);
  }

  D.solve();



  rep(i,0,m){
    if(need[i]){
      if(D.ans[i]){
        cout<<"YES\n";
        continue;
      }
      else if(need[i] == 2){
        if(D.ans2[i]){
          cout<<"YES\n";
          continue;
        }
      }

      cout<<"NO\n";
    }
  }



  // math -> gcd it all
  // Did u check N=1? Did you switch N,M?
}