#include <bits/stdc++.h>
using namespace std;
const int maxn = 3 * 100010;
const int maxm = 3 * 100010;
const int BUFF = 10 * 1010 * 1010;
const int block = 400;
int n, m;
int ans[maxm];
struct DSU {
  int fa[maxn], rk[maxn];
  int *where[BUFF], val[BUFF];
  int tot;
  void init() {
    tot = 0;
    for (int i = 0; i <= n; i++) fa[i] = i, rk[i] = 1;
  }
  int Find(int x) { return x == fa[x] ? x : Find(fa[x]); }
  int FastFind(int x) {
    if (x == fa[x]) return x;
    return fa[x] = Find(fa[x]);
  }
  void Union(int x, int y) {
    int a = Find(x), b = Find(y);
    if (a < b) swap(a, b);
    val[tot] = rk[a];
    where[tot++] = &rk[a];
    val[tot] = fa[b];
    where[tot++] = &fa[b];
    assert(tot <= BUFF);
    rk[a] += rk[b];
    fa[b] = a;
  }
  void FastUnion(int x, int y) {
    int a = Find(x), b = Find(y);
    if (a < b) swap(a, b);
    rk[a] += rk[b];
    fa[b] = a;
  }
  void rollback() {
    while (tot) {
      *where[tot - 1] = val[tot - 1];
      tot--;
    }
  }
};
DSU dsu;
struct Query {
  int op, x, y;
  int e0, e1;
};
Query q[maxm];
struct EDGE {
  int u, v;
  EDGE() {}
  EDGE(int u, int v) : u(u), v(v) {}
  bool operator<(const EDGE &rhs) const {
    if (u == rhs.u) return v < rhs.v;
    return u < rhs.u;
  }
};
EDGE edge[maxm * 2];
map<EDGE, int> id;
vector<int> cur;
int addEdge(struct EDGE e) {
  if (e.u > e.v) swap(e.u, e.v);
  if (!id.count(e)) {
    int k = id.size();
    edge[k] = e;
    id[e] = k;
  }
  return id[e];
}
int used[maxm * 2];
int state[maxm * 2];
void rebuild(int l) {
  int r = min(l + block - 1, m);
  dsu.init();
  memset(used, 0, sizeof(used));
  memset(state, 0, sizeof(state));
  for (int i = 1; i < l; i++) {
    if (q[i].op == 1) {
      int e = ans[i - 1] == 1 ? q[i].e1 : q[i].e0;
      used[e] = 1;
      state[e] ^= 1;
    }
  }
  for (int i = l; i <= r; i++) {
    if (q[i].op == 1) {
      used[q[i].e0] = used[q[i].e1] = 0;
    }
  }
  cur.clear();
  for (int i = 1; i < l; i++) {
    int e = ans[i - 1] == 1 ? q[i].e1 : q[i].e0;
    if (used[e] && state[e]) {
      state[e] = 0;
      dsu.FastUnion(edge[e].u, edge[e].v);
    }
    if (!used[e] && state[e]) {
      state[e] = 0;
      cur.push_back(e);
    }
  }
}
vector<int> ask;
int main() {
  scanf("%d %d", &n, &m);
  for (int i = 1; i <= m; i++) {
    scanf("%d %d %d", &q[i].op, &q[i].x, &q[i].y);
    if (q[i].op == 1) {
      EDGE e = EDGE(q[i].x % n + 1, q[i].y % n + 1);
      q[i].e1 = addEdge(e);
      e = EDGE((q[i].x - 1) % n + 1, (q[i].y - 1) % n + 1);
      q[i].e0 = addEdge(e);
    } else
      ask.push_back(i);
  }
  for (int i = 1; i <= m; i++) {
    if ((i - 1) % block == 0) {
      rebuild(i);
    }
    if (q[i].op == 1) {
      dsu.rollback();
      int e = (ans[i - 1] == 1 ? q[i].e1 : q[i].e0);
      auto it = find(cur.begin(), cur.end(), e);
      if (it == cur.end())
        cur.push_back(e);
      else
        cur.erase(it);
      ans[i] = ans[i - 1];
    } else {
      for (int i = 0; i < (int)cur.size(); i++) {
        int e = cur[i];
        dsu.Union(edge[e].u, edge[e].v);
      }
      int u = (q[i].x + ans[i - 1] - 1) % n + 1;
      int v = (q[i].y + ans[i - 1] - 1) % n + 1;
      ans[i] = (dsu.Find(u) == dsu.Find(v));
    }
  }
  for (int i = 0; i < (int)ask.size(); i++) {
    printf("%d", ans[ask[i]]);
  }
  printf("\n");
  return 0;
}
