module SimpleUndirectedGraphic
    require 'set'

    def reachable?(u, v)
        reached = false
        dfs(u, {:WHEN_VISIT => -> x { reached = true if x == v } })
        reached
    end

    def each_connected_component(&block)
        return enum_for(__method__) unless block_given?
        reached = Set.new
        each_node do |s|
            next if reached.include?(s)
            cc = Set[s]
            queue = [s]
            until queue.empty?
                u = queue.shift
                each_neighbour(u) do |v|
                    next if cc.include?(v)
                    cc << v
                    queue << v
                end
            end
            block.call(cc)
            reached += cc
        end
    end

    def connected_components
        each_connected_component.to_a
    end

    def dfs(root, callback = Hash.new())
        known = Set[
            :WHEN_VISIT,
            :WHEN_CHECK,
            :WHEN_MOVE,
            :WHEN_RETURN,
            :WHEN_LEAVE,
        ]
        callback.keys.each do |name|
            raise "unknown callback: #{name}" if ! known.include?(name)
        end

        f = nil
        f.call(root) if f = callback[:WHEN_VISIT]
        stack = [[root, to_enum(:each_neighbour, root)]]
        parent = { root => root }
        until stack.empty?
            u, itr = stack[-1]
            begin
                v = itr.next
                f.call(u, v) if f = callback[:WHEN_CHECK]
                next if v == parent[u]|| parent[v]

                stack << [v, to_enum(:each_neighbour, v)]
                parent[v] = u
                f.call(u, v) if f = callback[:WHEN_MOVE]

                f.call(v) if f = callback[:WHEN_VISIT]
            rescue StopIteration
                stack.pop
                f.call(u) if f = callback[:WHEN_LEAVE]
                if ! stack.empty?
                    f.call(stack[-1][0], u) if f = callback[:WHEN_RETURN]
                end
            end
        end
    end
end

class Hash
    include SimpleUndirectedGraphic
    alias each_node each_key
    def each_neighbour(u)
        self[u].each do |v|
            yield(v)
        end
    end
end

n, Q = gets.split.map(&:to_i)
U = Math.sqrt(Q).ceil

g0 = {}
(0..n-1).each do |u|
    g0[u] = Set.new
end

(Q / U.to_f).ceil.times do
    g = Marshal.load(Marshal.dump(g0))
    query = []
    U.times do
        query << gets.split.map(&:to_i) rescue break
    end

    target = []
    query.each do |q, u, v|
        if q != 3
            target << [u, v]
        end
    end

    save = Set.new
    target.each do |u, v|
        if g[u].include?(v)
            save << [u, v]
            g[u].delete(v)
            g[v].delete(u)
        end
    end

    conv = {}
    g.each_connected_component do |cc|
        rep = nil
        cc.each do |u|
            rep ||= u
            conv[u] = rep
        end
    end

    save.each do |u, v|
        g[u] << v
        g[v] << u
    end

    g2 = {}
    conv.each_value {|u| g2[u] = Set.new}
    g.each do |u, s|
        s.each do |v|
            x, y = conv[u], conv[v]
            next if x == y
            g2[x] << y
            g2[y] << x
        end
    end

    query.each do |q, u, v|
        x, y = conv[u], conv[v]
        if q == 1
            g0[u] << v
            g0[v] << u
            g2[x] << y
            g2[y] << x
        elsif q == 2
            g0[u].delete(v)
            g0[v].delete(u)
            g2[x].delete(y)
            g2[y].delete(x)
        else
            if x == y
                puts 'YES'
            elsif
                puts g2.reachable?(u, v) ? 'YES' : 'NO'
            end
        end
    end
end