#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;   }   