#include <iostream>
#include <cstdio>
#include <map>
#include <set>
using namespace std;
#define N_MAX 100010
multiset<int> M[N_MAX], N[N_MAX];
int n, m;
pair<int,int> op[N_MAX];
inline int calc(int x) {
    return ((x&(x-1))^x);
}
void aib_add(multiset<int> M[], int x, int val, int c) {
    for (int i = x; i <= n; i += calc(i)) {
        if (c == 1) {
            M[i].insert(val);
        }
        else {
            M[i].erase(val);
        }
    }
}
void add_edge(int a, int b) {
    aib_add(M, a, b, 1);
    aib_add(N, n-b+1, a, 1);
    op[++op[0].first] = make_pair(a, b);
}

void delete_edge(int x) {
    int a = op[x].first, b = op[x].second;
    aib_add(M, a, b, -1);
    aib_add(N, n-b+1, a, -1);
}

int query_aib(multiset<int> M[], int a, int b, int ra, int rb) {
    static multiset<int>::iterator it;
    for (int i = a-1; i > 0; i -= calc(i)) {
        it = M[i].lower_bound(ra);
        if (it != M[i].end() && *it <= rb) {
            return 0;
        }
    }
    return 1;
}

void query(int a, int b) {
    int sol = 1;
    sol &= query_aib(M, a, b, a, b);
    sol &= query_aib(N, n-b+1, a, a, b);
    if (sol) {
        printf("YES\n");
    } else {
        printf("NO\n");
    }
}
int main() {
   // freopen("input", "r", stdin);
    //freopen("output", "w", stdout);
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= m; i++) {
        int type, a, b;
        scanf("%d", &type);
        if (type == 1) {
            scanf("%d%d", &a, &b);
            add_edge(min(a, b), max(a, b));
        } else if (type == 2) {
            scanf("%d", &a);
            delete_edge(a);
        } else {
            scanf("%d%d", &a, &b);
            query(a, b);
        }
    }
    return 0;
}