/// Ovo mora da da WA na subtask 2, inace vazi teorema o srpskim takmicenjima...
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1005;
int N,Q;
bool moze[maxn][maxn];
vector<int> graf[maxn][30];
void spoj(int a,int b);
void sviparovi(vector<int> &A,vector<int> &B){
   if(moze[A[0]][B[0]]) /// Vec smo ih spoili
      return;
   for(int x:A)
      for(int y:B)
         if(!moze[x][y])
            spoj(x,y);
}
void spoj(int a,int b){
   //cout<<"SPAJAM "<<a<<" "<<b<<endl;
   moze[a][b]=true;
   moze[b][a]=true;
   for(int i=1;i<=26;i++){
      if(graf[a][i].size()==0)
         continue;
      if(graf[b][i].size()==0)
         continue;
      sviparovi(graf[b][i],graf[a][i]);
   }
   return;
}
void dodaj(int a,int b,int s){ /// graf od a dodaje vezu ka b sa slovom s. To rezultuje da neki sa kojima b moze biti sada mogu i sa a, dok pre nisu mogli
   vector<int> A;
   A.push_back(a);
   for(int i=1;i<=N;i++){
      if(!moze[b][i])
         continue;
      if(graf[i][s].size()==0)
         continue;
      sviparovi(graf[i][s],A);
   }
   graf[b][s].push_back(a);
}
void newedge(int a,int b,char x){
   x-='a'-1;
   dodaj(a,b,x);
   dodaj(b,a,x);
   spoj(a,b);
}
void solve(){
   bool case2=true;
   cin>>N>>Q;
   for(int i=1;i<=N;i++)
      moze[i][i]=true;
   while(Q--){
      int t,a,b;
      char c;
      cin>>t>>a>>b;
      if(t==1){
         cin>>c;
         if(c!='a')
            exit(-1);
         newedge(a,b,c);
      }
      else
         cout<<moze[a][b]<<"\n";
   }
}
/*
3 5
2 1 2
1 1 2 a
2 1 2
1 2 3 a
2 1 3
*/
void reset(){}
int main(){
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    int T=1;
    //cin>>T;
    while(T--){
        solve();
        reset();
    }
    return 0;
}