#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <string>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <algorithm>
#include <sstream>
#include <iostream>
#include <cassert>
using namespace std;

typedef long long ll;

#define REP(i, n) for (int i = 0; i < (int)(n); ++i)
#define FOR(i, a, b) for (int i = (a); i < (int)(b); ++i)
#define FOREQ(i, a, b) for (int i = (a); i <= (int)(b); ++i)
#define DEC(i, k) for (int i = (k); i >= 0; --i)
#define FORIT(i, c) for (__typeof((c).begin()) i = (c).begin(); i != (c).end(); ++i)
#define SZ(v) (int)((v).size())
#define MEMSET(v, h) memset((v), (h), sizeof(v))
#define FIND(m, w) ((m).find(w) != (m).end())
#define ALL(c) (c).begin(), (c).end()

struct Query {
  int type;
  int from;
  int to;
  Query() {;}
  Query(int type, int from, int to) : type(type), from(from), to(to) {;}
};

int n, k, sqk;
set<int> mainEdges[40010];
set<int> subEdges[410];
Query query[40010];
int mapto[40010];
int group[410];
int group_vertex[40010];
bool mainVisit[40010];
bool subVisit[410];

void mainDfs(int index, int g) {
  if (mainVisit[index]) { return; }
  mainVisit[index] = true;
  if (mapto[index] != -1) {
    group[mapto[index]] = g;
    group_vertex[g] = mapto[index];
  }
  FORIT(it, mainEdges[index]) {
    mainDfs(*it, g);
  }
}

bool subDfs(int index, int target) {
  if (index == target) { return true; }
  if (subVisit[index]) { return false; }
  subVisit[index] = true;
  FORIT(it, subEdges[index]) {
    if (subDfs(*it, target)) { return true; }
  }
  return false;
}

void solve(int start) {
  REP(i, 410) {
    subEdges[i].clear();
  }
  MEMSET(mapto, -1);
  MEMSET(group, -1);
  MEMSET(mainVisit, false);
  int cnt = 0;
  REP(i, sqk) {
    if (i + start >= k) { break; }
    Query mainQ = query[i + start];
    if (mapto[mainQ.from] == -1) {
      mapto[mainQ.from] = cnt++;
    }
    if (mapto[mainQ.to] == -1) {
      mapto[mainQ.to] = cnt++;
    }
    Query subQ = Query(mainQ.type, mapto[mainQ.from], mapto[mainQ.to]);
    assert(cnt <= 410);
    if (mainQ.type == 2) {
      if (mainEdges[mainQ.from].count(mainQ.to)) {
        subEdges[subQ.from].insert(subQ.to);
        subEdges[subQ.to].insert(subQ.from);
        mainEdges[mainQ.from].erase(mainQ.to);
        mainEdges[mainQ.to].erase(mainQ.from);
      }
    }
  }
  int g = 0;
  REP(i, n) {
    if (mainVisit[i]) { continue; }
    mainDfs(i, g);
    g++;
  }
  REP(i, cnt) {
    int g = group[i];
    if (i == group_vertex[g]) { continue; }
    subEdges[i].insert(group_vertex[g]);
    subEdges[group_vertex[g]].insert(i);
  }
  REP(i, sqk) {
    if (i + start >= k) { return; }
    Query mainQ = query[i + start];
    Query subQ = Query(mainQ.type, mapto[mainQ.from], mapto[mainQ.to]);
    if (mainQ.type == 1) {
      subEdges[subQ.from].insert(subQ.to);
      subEdges[subQ.to].insert(subQ.from);
      mainEdges[mainQ.from].insert(mainQ.to);
      mainEdges[mainQ.to].insert(mainQ.from);
    } else if (mainQ.type == 2) {
      if (group[subQ.from] != group[subQ.to]) {
        subEdges[subQ.from].erase(subQ.to);
        subEdges[subQ.to].erase(subQ.from);
      }
      if (mainEdges[mainQ.from].count(mainQ.to)) {
        mainEdges[mainQ.from].erase(mainQ.to);
        mainEdges[mainQ.to].erase(mainQ.from);
      }
    } else {
      MEMSET(subVisit, false);
      if (subDfs(subQ.from, subQ.to)) {
        puts("YES");
      } else {
        puts("NO");
      }
    }
  }
}

int main() {
  scanf("%d %d", &n, &k);
  sqk = (int)sqrt(k);
  REP(i, k) {
    int t, u, v;
    scanf("%d %d %d", &t, &u, &v);
    query[i] = Query(t, u, v);
  }
  REP(i, sqk + 10) {
    if (sqk * i > k) { break; }
    solve(i * sqk);
  }
}

Measured memory_bytes: 4520