#include <bits/stdc++.h>   using namespace std;   struct UnionFind {     int n;     vector<int> p, rank;     int findSet(int i) { return (p[i] == i ? i : (p[i] = findSet(p[i]))); }     bool isSameSet(int i, int j) { return (findSet(i) == findSet(j)); }     void unionSet(int i, int j) {       if (!isSameSet(i, j)) {         int x = findSet(i);         int y = findSet(j);         if (rank[x] > rank[y]) {           p[y] = x;         } else {           p[x] = y;         }         if (rank[x] == rank[y]) {           rank[y]++;         }       }     }     UnionFind(int _n) {       n = _n;       for (int i = 0; i < n; i++) {         p.push_back(i);         rank.push_back(0);       }     }   };   int n, m;   vector<int> P;   vector<int> type;   vector<pair<int, int> > query;   vector<pair<int, int> > t3;   vector<int> H;   void calculateHeight() {     vector<int> inDegree(n, 0);     for (int i = 0; i < n; i++) {       if (P[i] != -1) {         inDegree[P[i]] += 1;       }     }     H.resize(n, -1);     queue<int> q;     for (int i = 0; i < n; i++) {       if (inDegree[i] == 0) {         H[i] = 0;         q.push(i);       }     }     while (!q.empty()) {       int u = q.front();       q.pop();       if (P[u] == -1) {         continue;       }       H[P[u]] = max(H[P[u]], H[u] + 1);       inDegree[P[u]] -= 1;       if (inDegree[P[u]] == 0) {         q.push(P[u]);       }     }   }   set<pair<int, int> > isParent;   vector<vector<int> > G;   vector<vector<int> > Q;   vector<int> visited;   void dfs(int u) {     visited[u] = true;     for (int i = 0; i < Q[u].size(); i++) {       int p = Q[u][i];       if (visited[p]) {         isParent.insert(make_pair(p, u));       }     }     for (int i = 0; i < G[u].size(); i++) {       dfs(G[u][i]);     }     visited[u] = false;   }   int main() {     cin >> n >> m;     P.resize(n, -1);     G.resize(n);     Q.resize(n);     visited.resize(n, false);     type.resize(m);     query.resize(m);     for (int i = 0; i < m; i++) {       cin >> type[i];       if (type[i] == 1) {         cin >> query[i].first >> query[i].second;         query[i].first -= 1;         query[i].second -= 1;         P[query[i].first] = query[i].second;         G[query[i].second].push_back(query[i].first);       } else if (type[i] == 2) {         cin >> query[i].first;         query[i].first -= 1;       } else {         cin >> query[i].first >> query[i].second;         query[i].first -= 1;         query[i].second -= 1;         t3.push_back(make_pair(query[i].second, i));       }     }     int t3i = 0;     int doc = 0;     sort(t3.begin(), t3.end());     for (int i = 0; i < m; i++) {       if (type[i] == 2) {         for (; t3i < t3.size() && t3[t3i].first == doc; t3i++) {           int c = query[i].first;           int p = query[t3[t3i].second].first;           Q[c].push_back(p);         }         doc++;       }     }     for (int i = 0; i < n; i++) {       if (P[i] == -1) {         dfs(i);       }     }     UnionFind uf(n);     t3i = 0;     doc = 0;     for (int i = 0; i < m; i++) {       if (type[i] == 1) {         uf.unionSet(query[i].first, query[i].second);       } else if (type[i] == 2) {         for (; t3i < t3.size() && t3[t3i].first == doc; t3i++) {           int c = query[i].first;           int p = query[t3[t3i].second].first;           if (uf.isSameSet(c, p) && isParent.count(make_pair(p, c))) {             query[t3[t3i].second].second = true;           } else {             query[t3[t3i].second].second = false;           }         }         doc++;       }     }     for (int i = 0; i < m; i++) {       if (type[i] == 3) {         if (query[i].second) {           cout <<  YES n ;         } else {           cout <<  NO n ;         }       }     }   }