#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;   }