#include <bits/stdc++.h>
#pragma comment(linker, "/stack:102400000,102400000")
using namespace std;
int lowbit(int x) { return (x & -x); }
template <class T_>
T_ f_abs(T_ x) {
  return x < 0 ? -x : x;
}
template <class T_>
T_ f_max(T_ a, T_ b) {
  return a > b ? a : b;
}
template <class T_>
T_ f_min(T_ a, T_ b) {
  return a < b ? a : b;
}
template <class T_>
void chkmax(T_ &a, T_ b) {
  if (a == -1 || a < b) a = b;
}
template <class T_>
void chkmin(T_ &a, T_ b) {
  if (a == -1 || a > b) a = b;
}
template <class T_>
T_ gcd(T_ a, T_ b) {
  while (T_ t = a % b) a = b, b = t;
  return b;
}
template <class T_>
void f_swap(T_ &a, T_ &b) {
  T_ t = a;
  a = b;
  b = t;
}
const double eps = 1e-9;
const int dx[] = {-1, 1, 0, 0, -1, -1, 1, 1},
          dy[] = {0, 0, -1, 1, -1, 1, -1, 1};
const int inf = 0x7fffffff;
const int mod = 1000000007;
const int N = 100003;
const int MAXV = 100003;
int n, m, cnt, who[N], dsu[N];
bool vis[N], tree[N << 2];
vector<pair<int, int> > vt[N], qu[N];
struct Oper {
  int tp, x, y;
  bool tag;
  Oper() {}
  Oper(int tp_, int x_, int y_) {
    tp = tp_;
    x = x_;
    y = y_;
  }
} op[N];
struct Edge {
  int to, next;
} edg[MAXV << 1];
int total, idx, root, first[MAXV];
int siz[MAXV];
int dep[MAXV];
int top[MAXV];
int fa[MAXV];
int son[MAXV];
int id[MAXV];
void Dfs_1(int u) {
  int e, v, i;
  siz[u] = 1;
  son[u] = 0;
  for (e = 0; e < (int)vt[u].size(); ++e) {
    v = vt[u][e].first;
    i = vt[u][e].second;
    op[i].tag = !vis[v];
  }
  vis[u] = true;
  for (e = first[u]; ~e; e = edg[e].next) {
    v = edg[e].to;
    if (v != fa[u]) {
      fa[v] = u;
      dep[v] = dep[u] + 1;
      Dfs_1(v);
      if (son[u] == 0 || siz[v] > siz[son[u]]) son[u] = v;
      siz[u] += siz[v];
    }
  }
  for (e = 0; e < (int)vt[u].size(); ++e) {
    v = vt[u][e].first;
    i = vt[u][e].second;
    if (op[i].tag && !vis[v]) op[i].tag = false;
  }
}
void Dfs_2(int u, int tp) {
  id[u] = ++idx;
  top[u] = tp;
  if (son[u] != 0) Dfs_2(son[u], top[u]);
  for (int e = first[u]; ~e; e = edg[e].next) {
    int v = edg[e].to;
    if (v != son[u] && v != fa[u]) Dfs_2(v, v);
  }
}
void BuildChain() {
  Dfs_1(root);
  Dfs_2(root, root);
}
void Build(int l, int r, int root) {
  tree[root] = false;
  if (l == r) return;
  int mid = ((l + r) >> 1);
  Build(l, mid, (root << 1));
  Build(mid + 1, r, (root << 1 | 1));
}
void Update(int p, int l, int r, int root) {
  if (l == r) {
    tree[root] = true;
    return;
  }
  int mid = ((l + r) >> 1);
  if (p <= mid)
    Update(p, l, mid, (root << 1));
  else
    Update(p, mid + 1, r, (root << 1 | 1));
  tree[root] = (tree[(root << 1)] && tree[(root << 1 | 1)]);
}
bool Query(int L, int R, int l, int r, int root) {
  if (L <= l && r <= R) return tree[root];
  int mid = ((l + r) >> 1);
  bool res = true;
  if (L <= mid) res = (res && Query(L, R, l, mid, (root << 1)));
  if (R > mid) res = (res && Query(L, R, mid + 1, r, (root << 1 | 1)));
  return res;
}
bool FindChain(int u, int v) {
  int u_top = top[u], v_top = top[v], L, R;
  while (u_top != v_top) {
    if (dep[u_top] < dep[v_top]) {
      f_swap(u_top, v_top);
      f_swap(u, v);
    }
    L = id[u_top];
    R = id[u];
    if (!Query(L, R, 1, idx, 1)) return false;
    u = fa[u_top];
    u_top = top[u];
  }
  if (u != v) {
    if (dep[u] > dep[v]) f_swap(u, v);
    L = id[son[u]];
    R = id[v];
    if (!Query(L, R, 1, idx, 1)) return false;
  }
  return true;
}
void addedge(int from, int to) {
  edg[total].to = to;
  edg[total].next = first[from];
  first[from] = total++;
}
void Init() {
  cnt = 0;
  root = n + 1;
  total = idx = fa[root] = dep[root] = 0;
  for (int i = 1; i <= n + 1; ++i) {
    first[i] = -1;
    dsu[i] = i;
    vt[i].clear();
    vis[i] = false;
  }
}
void GetData() {
  int tp, x, y;
  for (int i = 0; i < m; ++i) {
    scanf("%d%d", &tp, &x);
    if (tp != 2) scanf("%d", &y);
    if (tp == 1) {
      dsu[x] = y;
      addedge(y, x);
    } else if (tp == 2) {
      y = -1;
      who[++cnt] = x;
      qu[cnt].clear();
    } else {
      vt[x].push_back(make_pair(who[y], i));
      qu[y].push_back(make_pair(x, i));
    }
    op[i] = Oper(tp, x, y);
  }
}
void Solve() {
  int i, j, tp, p;
  bool flag;
  for (i = 1; i <= n; ++i) {
    if (dsu[i] == i) addedge(n + 1, i);
  }
  BuildChain();
  Build(1, idx, 1);
  for (i = cnt = 0; i < m; ++i) {
    tp = op[i].tp;
    if (tp == 1)
      Update(id[op[i].x], 1, idx, 1);
    else if (tp == 2) {
      ++cnt;
      for (j = 0; j < (int)qu[cnt].size(); ++j) {
        p = qu[cnt][j].second;
        if (op[p].tag)
          flag = FindChain(who[cnt], qu[cnt][j].first);
        else
          flag = false;
        vis[p] = flag;
      }
    }
  }
  for (i = 0; i < m; ++i) {
    if (op[i].tp == 3) puts(vis[i] ? "YES" : "NO");
  }
}
int main() {
  while (~scanf("%d%d", &n, &m)) {
    Init();
    GetData();
    Solve();
  }
  return 0;
}
