#include <bits/stdc++.h>

using namespace std;

struct DSU {
    int n;
    vector<int> parent;
    DSU(int _n) {
        n = _n;
        parent.resize(n);
        for(int i = 0; i < n; i++) parent[i] = i;
    }
    int find_parent(int u) {
        if(u == parent[u]) return u;
        return parent[u] = find_parent(parent[u]);
    }
    bool check(int u, int v) {
        u = find_parent(u);
        v = find_parent(v);
        return u == v;
    }
    void join(int u, int v) {
        u = find_parent(u);
        v = find_parent(v);
        if(u != v) parent[u] = v;
    }
};

struct query {
    int t, u, v;
    char c;
};

struct edge {
    int u, v;
    edge() { u = 0; v = 0; }
    edge(int _u, int _v) { u = _u; v = _v; }
};

const int N = 1e2 + 10, M = 3e5 + 10, MX = 1e4 + 100;
int n, q;
query QS[M];
vector<edge> edges[26];
DSU dsu(MX);
const int fake = MX - 1;

int f(int i, int j) { return (i - 1) * n + j - 1; }

void Merge(int u1, int u2, int v1, int v2) {
    dsu.join(f(u1, u2), f(v1, v2));
    dsu.join(f(u2, u1), f(v2, v1));
}

void Merge(edge x, edge y) {
    Merge(x.u, y.u, x.v, y.v);
    Merge(x.u, y.v, x.v, y.u);
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cin >> n >> q;
    for(int i = 0; i < q; i++) {
        cin >> QS[i].t >> QS[i].u >> QS[i].v;
        if(QS[i].t == 1) cin >> QS[i].c;
    }
    for(int i = 1; i <= n; i++) dsu.join(fake, f(i, i));
    for(int qind = 0; qind < q; qind++) {
        int t = QS[qind].t, u = QS[qind].u, v = QS[qind].v;
        if(t == 1) {
            char ch = QS[qind].c;
            int c = (int)(ch - 'a');
            edge edg = edge(u, v);
            for(edge e : edges[c]) Merge(edg, e);
            edges[c].push_back(edg);
            dsu.join(f(u, v), fake);
            dsu.join(f(v, u), fake);
        } else {
            cout << dsu.check(f(u, v), fake) << "\n";
        }
    }
    return 0;
}