#include <iostream>
#include <fstream>
#include <vector>
#include <set>

using namespace std;

const int Nmax = 100001;
const int Mmax = 400001;
const int inf = 1000000000;

struct SegmentTree
{
    int minim, maxim;

} Arb[4 * Nmax];

set <int> G[Nmax];

int x[Mmax], y[Mmax];

int N, M;

void update( int nod, int st, int dr, int pos )
{
    if ( st == dr )
    {
        Arb[nod].minim = inf;
        Arb[nod].maxim = 0;

        if ( G[pos].size() )
        {
            set<int>::iterator it = G[pos].begin();

            Arb[nod].minim = *it;

            set<int>::iterator rit = G[pos].end();
            --rit;

            Arb[nod].maxim = *rit;
        }
    }
    else
    {
        int m = ( st + dr ) / 2;

        if ( pos <= m )
                update( 2 * nod, st, m, pos );
        else
                update( 2 * nod + 1, m + 1, dr, pos );

        Arb[nod].minim = min( Arb[2 * nod].minim, Arb[2 * nod + 1].minim );
        Arb[nod].maxim = max( Arb[2 * nod].maxim, Arb[2 * nod + 1].maxim );
    }
}

int minim = inf;
int maxim = 0;

void query( int nod, int st, int dr, int st_query, int dr_query )
{
    if ( st_query <= st && dr <= dr_query )
    {
        minim = min( minim, Arb[nod].minim );
        maxim = max( maxim, Arb[nod].maxim );
    }
    else
    {
        int m = ( st + dr ) / 2;

        if ( st_query <= m )
                query( 2 * nod, st, m, st_query, dr_query );

        if ( m < dr_query )
                query( 2 * nod + 1, m + 1, dr, st_query, dr_query );
    }
}

void build( int nod, int st, int dr )
{
    if ( st == dr )
    {
        Arb[nod].minim = inf;
        Arb[nod].maxim = 0;
    }
    else
    {
        int m = ( st + dr ) / 2;

        build( 2 * nod, st, m );
        build( 2 * nod + 1, m + 1, dr );

        Arb[nod].minim = min( Arb[2 * nod].minim, Arb[2 * nod + 1].minim );
        Arb[nod].maxim = max( Arb[2 * nod].maxim, Arb[2 * nod + 1].maxim );
    }
}

int contor = 0;

int main()
{
    ///ifstream cin("date.in");

    cin >> N >> M;

    build( 1, 1, N );

    for ( int i = 1; i <= M; ++i )
    {
        int tip, a, b;

        cin >> tip;

        if ( tip == 1 )
        {
            cin >> a >> b;

            contor++;

            x[contor] = a;
            y[contor] = b;

            G[a].insert( b );
            G[b].insert( a );

            update( 1, 1, N, a );
            update( 1, 1, N, b );
        }

        if ( tip == 2 )
        {
            cin >> a;

            int st = x[a], dr = y[a];

            G[st].erase( dr );
            G[dr].erase( st );

            update( 1, 1, N, st );
            update( 1, 1, N, dr );
        }

        if ( tip == 3 )
        {
            cin >> a >> b;

            minim = inf;
            maxim = 0;

            query( 1, 1, N, a, b );

            if ( a <= minim && minim <= b && a <= maxim && maxim <= b )
            {
                cout << "YES\n";
            }
            else
            {
                cout << "NO\n";
            }
        }
    }

    return 0;
}