import java.io.*;
import java.util.*;

public class Main {
    // 存储节点 i 的父节点编号;当 parent[i] == i 时,i 为该集合的根节点
    private static int[] parent;
    // 仅在 i 为根节点时有效,记录以 i 为根的集合中包含的元素总数
    private static int[] size;

    public static void main(String[] args) throws IOException {
        // 使用高性能输入输出流
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));

        // 解析输入首行的 n (元素总数) 和 q (操作总数)
        String[] strA = br.readLine().trim().split("\\s+");
        int n = Integer.parseInt(strA[0]);
        int q = Integer.parseInt(strA[1]);

        parent = new int[n + 1];
        size = new int[n + 1];
        for (int i = 1; i <= n; i++) {
            // 初始状态下,每个元素自成一个集合,父节点指向自己
            parent[i] = i;
            // 每个初始集合的大小均为 1
            size[i] = 1;
        }

        while (q-- > 0) {
            String[] strB = br.readLine().trim().split("\\s+");
            int op = Integer.parseInt(strB[0]); // 操作类型编号

            switch (op) {
                case 1: {
                    // 合并操作:将 i 和 j 所在的两个集合合并为一个
                    int i = Integer.parseInt(strB[1]);
                    int j = Integer.parseInt(strB[2]);
                    union(i, j);
                    break;
                }
                case 2: {
                    // 判断 i 和 j 是否属于同一个集合
                    int i = Integer.parseInt(strB[1]);
                    int j = Integer.parseInt(strB[2]);
                    // 若两者的根节点相同,则在同一集合,输出 YES
                    out.println(find(i) == find(j) ? "YES" : "NO");
                    break;
                }
                case 3: {
                    // 获取 i 所在集合的元素总数
                    int i = Integer.parseInt(strB[1]);
                    // 必须先通过 find(i) 找到根节点,因为只有根节点的 size 是准确的
                    out.println(size[find(i)]);
                    break;
                }
            }
        }

        // 刷新缓冲区并释放 IO 资源
        out.flush();
        out.close();
        br.close();
    }

    /**
     * 查找元素 i 所在集合的根节点
     * 在递归查找过程中,将路径上所有节点的父节点直接指向根节点
     */
    private static int find(int i) {
        // 如果自己就是根节点,直接返回
        if (parent[i] == i) {
            return i;
        }
        // 将查找到的根节点赋值给当前节点的 parent 数组
        return parent[i] = find(parent[i]);
    }

    /**
     * 将包含 i 和 j 的两个集合合并
     *
     * @param i 第一个元素
     * @param j 第二个元素
     */
    private static void union(int i, int j) {
        // 分别获取两个元素当前的根节点
        int rootI = find(i);
        int rootJ = find(j);

        // 如果根节点不同,说明处于不同集合,执行合并
        if (rootI != rootJ) {
            // 将 I 集合的根节点挂载到 J 集合的根节点之下
            parent[rootI] = rootJ;
            // 将被合并集合的规模累加到新的根节点 (rootJ) 上
            size[rootJ] += size[rootI];
        }
    }
}