#include <bits/stdc++.h>
#pragma GCC optimize("O3")
using namespace std;
template <typename T>
void _R(T &x) {
  cin >> x;
}
void _R(int &x) { scanf("%d", &x); }
void _R(long long &x) { scanf("%" PRId64, &x); }
void _R(double &x) { scanf("%lf", &x); }
void _R(char &x) { scanf(" %c", &x); }
void _R(char *x) { scanf("%s", x); }
void R() {}
template <typename T, typename... U>
void R(T &head, U &...tail) {
  _R(head);
  R(tail...);
}
template <typename T>
void _W(const T &x) {
  cout << x;
}
void _W(const int &x) { printf("%d", x); }
template <typename T>
void _W(const vector<T> &x) {
  for (auto i = x.cbegin(); i != x.cend(); i++) {
    if (i != x.cbegin()) putchar(' ');
    _W(*i);
  }
}
void W() {}
template <typename T, typename... U>
void W(const T &head, const U &...tail) {
  _W(head);
  putchar(sizeof...(tail) ? ' ' : '\n');
  W(tail...);
}
const int N = 1e5 + 10;
const int M = 1e5 + 10;
struct Q {
  int op, a, b;
  void read() {
    R(op);
    if (op == 1 || op == 3)
      R(a, b);
    else if (op == 2)
      R(a);
    else
      assert(0);
  }
} q[M];
vector<int> v[N];
bool ans[M];
int f[N], tag[N], t;
int main() {
  int n, m;
  R(n, m);
  for (int i = 0; i < int(m); i++) q[i].read();
  for (int i = 0; i < int(m); i++)
    if (q[i].op == 3) v[q[i].b].push_back(i);
  for (int i = (1); i <= int(n); i++) f[i] = 0;
  int nd = 0;
  for (int i = 0; i < int(m); i++) {
    if (q[i].op == 1) {
      f[q[i].a] = q[i].b;
    } else if (q[i].op == 2) {
      nd++;
      t++;
      for (int x = q[i].a; x; x = f[x]) tag[x] = t;
      for (int j : v[nd]) ans[j] = (tag[q[j].a] == t);
    } else if (q[i].op == 3) {
      continue;
    } else
      assert(0);
  }
  for (int i = 0; i < int(m); i++)
    if (q[i].op == 3) W(ans[i] ? "YES" : "NO");
  return 0;
}
