#include <iostream>
#include <fstream>
#include <vector>
#include <queue>
#include <tuple>
using namespace std;
ifstream f("citire.in");
ofstream g("afisare.out");
class Graf
{
private:
int Noduri, Muchii;
vector <vector<int>> ListaAdiacenta;
public:
Graf(){}
Graf(int Noduri)
{
this->Noduri = Noduri;
}
Graf( int Noduri, int Munchii, vector <vector<int>> ListaAdiacenta)
{
this->Noduri = Noduri;
this->Muchii = Muchii;
this->ListaAdiacenta= ListaAdiacenta;
}
~Graf()
{
this->Noduri = 0;
this->Muchii = 0;
this->ListaAdiacenta.clear();
}
void SetNoduri(int n)
{
Noduri = n;
}
int GetNoduri()
{
return Noduri;
}
void SetMuchii(int m)
{
Muchii = m;
}
int GetMuchii()
{
return Muchii;
}
void codBFS(int s);
void codDFS(int nod, vector <bool> & vizitat);
int ComponenteConexe();
void CodSortareTopo(int grad_intern[]);
int Cautare(int nod, vector <int> &radacina);
void Reuniune(int x, int y, vector <int> &radacina);
vector <string> CodDisjoint(vector <pair<int, pair<int, int>>>operatii);
};
void Graf::codBFS(int s)
{
queue <int> coada;
int distanta[Noduri+1] = {0};
bool vizitat[Noduri+1] = {false};
vizitat[s] = true;
coada.push(s);
while(coada.size()!= 0)
{
for (int nod : ListaAdiacenta[coada.front()])
{
if(vizitat[nod]==false)
{
vizitat[nod]=true;
distanta[nod]=distanta[coada.front()]+1;
coada.push(nod);
}
}
coada.pop();
}
for(int i= 1; i <= Noduri; i++)
if(s!=i && distanta[i]==0)
g<<-1<<' ';
else
g<<distanta[i]<<' ';
}
void Bfs()
{
int n, m, x, y, s;
f>>n>>m>>s;
vector <vector<int>> ListaAdiacenta(n+1);
for(int i= 0; i < m; i++)
{
f>>x>>y;
ListaAdiacenta[x].push_back(y);
}
Graf G(n, m, ListaAdiacenta);
G.codBFS(s);
}
void Graf::codDFS(int nod, vector <bool>& vizitat)
{
vizitat[nod]=true;
for(int i : ListaAdiacenta[nod])
{
if(vizitat[i]==false)
codDFS(i, vizitat);
}
}
int Graf::ComponenteConexe()
{
vector <bool> vizitat(Noduri+ 1, false);
int nr = 0;
for(int i=1; i<=Noduri; i++)
if(vizitat[i]==false)
{
nr++;
codDFS(i, vizitat);
}
return nr;
}
void Dfs()
{
int n, m, x, y;
f>>n>>m;
vector <vector<int>> ListaAdiacenta(n+1);
for(int i=0; i < m; i++)
{
f>>x>>y;
ListaAdiacenta[x].push_back(y);
ListaAdiacenta[y].push_back(x);
}
Graf G(n, m, ListaAdiacenta);
g<<G.ComponenteConexe();
}
void Graf::CodSortareTopo(int grad_intern[])
{
queue <int> coada;
vector <int> afisare;
for(int i=1; i<=Noduri; i++)
if(grad_intern[i]==0)
coada.push(i);
while(coada.size()!=0)
{
int nod = coada.front();
afisare.push_back(nod);
coada.pop();
for (int i : ListaAdiacenta[nod])
{
grad_intern[i]--;
if(grad_intern[i]==0)
coada.push(i);
}
}
for(auto i = afisare.begin(); i!=afisare.end(); i++)
g<<*i<<' ';
}
void SortareTopologica()
{
int n, m, x, y;
f>>n>>m;
int grad_intern[50001]={0};
vector <vector<int>> ListaAdiacenta(n+1);
for(int i=0; i < m; i++)
{
f>>x>>y;
ListaAdiacenta[x].push_back(y);
grad_intern[y]++;
}
Graf G(n, m, ListaAdiacenta);
G.CodSortareTopo(grad_intern);
}
int Graf::Cautare(int nod, vector<int>&radacina)
{
if(radacina[nod]!=nod)
radacina[nod]=Cautare(radacina[nod], radacina);
return radacina[nod];
}
void Graf::Reuniune(int x, int y, vector<int>&radacina)
{
int radx, rady;
radx=Cautare(x, radacina);
rady=Cautare(y, radacina);
radacina[radx]=rady;
}
vector <string> Graf::CodDisjoint(vector <pair<int, pair<int, int>>>operatii)
{
vector <string> solutie;
vector <int> radacina(Noduri+1);
for(int i=1;i<=Noduri; i++)
radacina[i]=i;
for(int i=0; i < operatii.size();i++)
{
int op = operatii[i].first;
int x = operatii[i].second.first;
int y = operatii[i].second.second;
if(op==1)
Reuniune(x, y, radacina);
else
{
if(Cautare(x, radacina)==Cautare(y, radacina))
solutie.push_back("DA");
else
solutie.push_back("NU");
}
}
return solutie;
}
void Disjoint()
{
int N, M, op, x, y;
f>>N>>M;
Graf G(N);
vector <pair<int, pair<int, int>>>operatii;
for(int i=0; i<M; i++)
{
f>>op>>x>>y;
operatii.push_back(make_pair(op, make_pair(x, y)));
}
vector<string>afisare=G.CodDisjoint(operatii);
for(auto i=afisare.begin(); i!=afisare.end(); i++)
g<<*i<<endl;
}
int main()
{
Disjoint();
f.close();
g.close();
return 0;
}