#include <iostream>
using namespace std;

typedef long long ll;

const ll mod = 1e9 + 7;
ll dp[2002];

int main() {
  ll n;
  cin >> n;
  fill(dp + 3, dp + n + 1, 1);
  for (int i = 4; i <= n; i++) {
    for (int j = i - 3; j >= 3; j--) {
      dp[i] = (dp[i] + dp[j]) % mod;
    }
  }
  cout << dp[n] << endl;
}

#include <iostream>
using namespace std;

typedef long long ll;

const ll mod = 1e9 + 7;
ll dp[2005];

int main() {
  ll n;
  cin >> n;
  dp[0] = 1;
  for (int i = 3; i <= n; i++) {
    for (int j = i - 3; j >= 0; j--) {
      dp[i] = (dp[i] + dp[j]) % mod;
    }
  }
  cout << dp[n] << endl;
}


#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
#include <vector>

using namespace std;
typedef long long ll;
const int MOD = 1e9 + 7;
int dp[2100][2100]; // dp[i][j] 长度为i的序列和为j 的方案数

int main() {
  int S;
  scanf("%d", &S);
  dp[0][0] = 1;
  for (int i = 3; i <= S; i++) {       // sum
    for (int j = 1; j <= i / 3; j++) { // length
      for (int k = 3; k <= i; k++) {   // next
        dp[j][i] = (dp[j][i] + dp[j - 1][i - k]) % MOD;
      }
    }
  }
  int ans = 0;
  for (int i = 1; i <= S / 3; i++) {
    ans = (ans + dp[i][S]) % MOD;
  }
  printf("%d\\n", ans);
  return 0;
}

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
#include <vector>

using namespace std;
typedef long long ll;
const int MOD = 1e9 + 7;
int dp[2100]; // dp[i] 和为 i 的方案数

int main() {
  int S;
  scanf("%d", &S);
  dp[0] = 1;
  for (int i = 3; i <= S; i++) {   // sum
    for (int k = 3; k <= i; k++) { // next
      dp[i] = (dp[i] + dp[i - k]) % MOD;
    }
  }
  printf("%d\\n", dp[S]);
  return 0;
}


#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <map>
#define ll long long
#define lson (rt << 1)
#define rson (rt << 1 | 1)
#define gmid ((l + r) >> 1)
using namespace std;

const int p = 1e9 + 7;

int f[2002][2002];

int main() {
  int n;
  cin >> n;
  int k = n / 3;
  f[0][0] = 1;
  for (int i = 3; i <= n; ++i)
    for (int j = 1; j <= i / 3; ++j)
      for (int k = 3; k <= i - j + 1; ++k)
        f[i][j] = (f[i][j] + f[i - k][j - 1]) % p;
  long long ans = 0;
  for (int j = 1; j <= n / 3; ++j)
    ans = (ans + f[n][j]) % p;
  cout << ans << endl;
}

#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <map>
#define ll long long
#define lson (rt << 1)
#define rson (rt << 1 | 1)
#define gmid ((l + r) >> 1)
using namespace std;

const int p = 1e9 + 7;

int f[2002];

int main() {
  int n;
  cin >> n;
  f[0] = 1;
  for (int i = 0; i <= n; ++i)
    for (int j = 3; j + i <= n; ++j)
      f[i + j] = (f[i + j] + f[i]) % p;
  cout << f[n] << endl;
}


#include "bits/stdc++.h"
using namespace std;
typedef long long ll;

template <typename T>
void print_vec(const vector<T> &v, bool is_reverse = false, int num = 0) {
  if (num == 0)
    num = (int)v.size();
  if (is_reverse)
    for (int i = num - 1; i >= 0; i--) {
      cout << v[i];
      if (i != 0)
        cout << " ";
    }
  else
    for (int i = 0; i < num; i++) {
      cout << v[i];
      if (i != num - 1)
        cout << " ";
    }
  cout << endl;
}

template <typename T> void print_pairvec(const vector<T> &v, int num = 0) {
  if (num == 0)
    num = (int)v.size();
  cout << endl;
  for (int i = 0; i < num; i++) {
    cout << v[i].first << " " << v[i].second << endl;
  }
}

template <typename TYPE> void print_vec2(const vector<vector<TYPE>> &v) {
  cout << endl;
  cout << "       ";
  for (int i = 0; i < v[0].size(); i++)
    cout << i << "   ";
  cout << endl;
  for (int i = 0; i < v.size(); i++) {
    cout << "i=" << i << ":   ";
    for (int j = 0; j < v[i].size(); j++) {
      if (v[i][j] == 0)
        cout << "\\x1B[0m" << v[i][j] << "   ";
      else
        cout << "\\x1B[31m" << v[i][j]
             << "   "; // https://stackoverrun.com/ja/q/12618775
    }
    cout << "\\x1B[0m" << endl;
  }
}

// auto mod int
// https://youtu.be/L8grWxBlIZ4?t=9858
// https://youtu.be/ERZuLAxZffQ?t=4807 : optimize
// https://youtu.be/8uowVvQ_-Mo?t=1329 : division
const int mod = 1000000007;
// const int mod = 998244353;
struct mint {
  ll x; // typedef long long ll;
  mint(ll x = 0) : x((x % mod + mod) % mod) {}
  mint operator-() const { return mint(-x); }
  mint &operator+=(const mint a) {
    if ((x += a.x) >= mod)
      x -= mod;
    return *this;
  }
  mint &operator-=(const mint a) {
    if ((x += mod - a.x) >= mod)
      x -= mod;
    return *this;
  }
  mint &operator*=(const mint a) {
    (x *= a.x) %= mod;
    return *this;
  }
  mint operator+(const mint a) const { return mint(*this) += a; }
  mint operator-(const mint a) const { return mint(*this) -= a; }
  mint operator*(const mint a) const { return mint(*this) *= a; }
  mint pow(ll t) const {
    if (!t)
      return 1;
    mint a = pow(t >> 1);
    a *= a;
    if (t & 1)
      a *= *this;
    return a;
  }

  // for prime mod
  mint inv() const { return pow(mod - 2); }
  mint &operator/=(const mint a) { return *this *= a.inv(); }
  mint operator/(const mint a) const { return mint(*this) /= a; }
};
istream &operator>>(istream &is, mint &a) { return is >> a.x; }
ostream &operator<<(ostream &os, const mint &a) { return os << a.x; }

int main() {
  int S;
  cin >> S;

  const int DIGIT = 667;
  const int MAX = 2000;
  vector<vector<mint>> dp(DIGIT + 5, vector<mint>(MAX + 5, 0));
  dp[0][0] = 1;
  for (int i = 0; i <= DIGIT; i++) {
    for (int j = 0; j <= MAX; j++) {
      for (int num = 3; num <= MAX; num++) {
        if (num + j <= MAX)
          dp[i + 1][j + num] += dp[i][j];
      }
    }
  }

  mint ans = 0;
  for (int i = 0; i <= DIGIT; i++)
    ans += dp[i][S];
  cout << ans << endl;
  return 0;
}

#include "bits/stdc++.h"
using namespace std;
typedef long long ll;

template <typename T>
void print_vec(const vector<T> &v, bool is_reverse = false, int num = 0) {
  if (num == 0)
    num = (int)v.size();
  if (is_reverse)
    for (int i = num - 1; i >= 0; i--) {
      cout << v[i];
      if (i != 0)
        cout << " ";
    }
  else
    for (int i = 0; i < num; i++) {
      cout << v[i];
      if (i != num - 1)
        cout << " ";
    }
  cout << endl;
}

template <typename T> void print_pairvec(const vector<T> &v, int num = 0) {
  if (num == 0)
    num = (int)v.size();
  cout << endl;
  for (int i = 0; i < num; i++) {
    cout << v[i].first << " " << v[i].second << endl;
  }
}

template <typename TYPE> void print_vec2(const vector<vector<TYPE>> &v) {
  cout << endl;
  cout << "       ";
  for (int i = 0; i < v[0].size(); i++)
    cout << i << "   ";
  cout << endl;
  for (int i = 0; i < v.size(); i++) {
    cout << "i=" << i << ":   ";
    for (int j = 0; j < v[i].size(); j++) {
      if (v[i][j] == 0)
        cout << "\\x1B[0m" << v[i][j] << "   ";
      else
        cout << "\\x1B[31m" << v[i][j]
             << "   "; // https://stackoverrun.com/ja/q/12618775
    }
    cout << "\\x1B[0m" << endl;
  }
}

// auto mod int
// https://youtu.be/L8grWxBlIZ4?t=9858
// https://youtu.be/ERZuLAxZffQ?t=4807 : optimize
// https://youtu.be/8uowVvQ_-Mo?t=1329 : division
const int mod = 1000000007;
// const int mod = 998244353;
struct mint {
  ll x; // typedef long long ll;
  mint(ll x = 0) : x((x % mod + mod) % mod) {}
  mint operator-() const { return mint(-x); }
  mint &operator+=(const mint a) {
    if ((x += a.x) >= mod)
      x -= mod;
    return *this;
  }
  mint &operator-=(const mint a) {
    if ((x += mod - a.x) >= mod)
      x -= mod;
    return *this;
  }
  mint &operator*=(const mint a) {
    (x *= a.x) %= mod;
    return *this;
  }
  mint operator+(const mint a) const { return mint(*this) += a; }
  mint operator-(const mint a) const { return mint(*this) -= a; }
  mint operator*(const mint a) const { return mint(*this) *= a; }
  mint pow(ll t) const {
    if (!t)
      return 1;
    mint a = pow(t >> 1);
    a *= a;
    if (t & 1)
      a *= *this;
    return a;
  }

  // for prime mod
  mint inv() const { return pow(mod - 2); }
  mint &operator/=(const mint a) { return *this *= a.inv(); }
  mint operator/(const mint a) const { return mint(*this) /= a; }
};
istream &operator>>(istream &is, mint &a) { return is >> a.x; }
ostream &operator<<(ostream &os, const mint &a) { return os << a.x; }

// combination mod prime
// https://www.youtube.com/watch?v=8uowVvQ_-Mo&feature=youtu.be&t=1619
struct combination {
  vector<mint> fact, ifact;
  combination(int n) : fact(n + 1), ifact(n + 1) {
    assert(n < mod);
    fact[0] = 1;
    for (int i = 1; i <= n; ++i)
      fact[i] = fact[i - 1] * i;
    ifact[n] = fact[n].inv();
    for (int i = n; i >= 1; --i)
      ifact[i - 1] = ifact[i] * i;
  }
  mint operator()(int n, int k) {
    if (k < 0 || k > n)
      return 0;
    return fact[n] * ifact[k] * ifact[n - k];
  }
};

int main() {
  int S;
  cin >> S;

  const int DIGIT = 667;
  const int MAX = 2000;
  combination comb(MAX + 5);

  mint ans = 0;
  for (int i = 0; i <= DIGIT; i++) {
    int tmp = S - 3 * (i + 1);
    // cout << " i: " << i << " tmp: " << tmp << " comb(tmp, i): " << comb(tmp,
    // i) << endl;
    ans += comb(tmp + i, i);
  }
  cout << ans << endl;

  // TLE解答
  // const int DIGIT = 667;
  // const int MAX = 2000;
  // vector<vector<mint>> dp(DIGIT+5, vector<mint>(MAX+5, 0));
  // dp[0][0] = 1;
  // for(int i=0; i<=DIGIT; i++){
  //   for(int j=0; j<=MAX; j++){
  //     for(int num=3; num<=MAX; num++){
  //       if(num+j <= MAX) dp[i+1][j+num] += dp[i][j];
  //     }
  //   }
  // }

  // mint ans = 0;
  // for(int i=0; i<=DIGIT; i++) ans += dp[i][S];
  // cout << ans << endl;
  return 0;
}


#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
#define pa pair<int, int>
#define pal pair<long long, long long>
#define pali pair<long long, int>
#define pad pair<double, double>
#define pb push_back
#define mp make_pair
#define COUT(v)                                                                \\
  for (int64_t i = 0; i < (v).size(); ++i) {                                   \\
    cout << v.at(i) << endl;                                                   \\
  }
#define REP(i, n) for (int64_t i = 0; i < n; ++i)
#define FOR(i, r, n) for (int64_t i = (r); i < n; ++i)
#define VIN(v)                                                                 \\
  for (int64_t i = 0; i < (v).size(); ++i) {                                   \\
    cin >> (v).at(i);                                                          \\
  }

typedef vector<bool> bvec;
typedef vector<int> ivec;
typedef vector<long long> lvec;
typedef vector<double> dvec;
typedef vector<pa> pavec;
typedef vector<pali> palivec;
typedef vector<pal> palvec;

typedef vector<vector<bool>> bmat;
typedef vector<vector<int>> imat;
typedef vector<vector<long long>> lmat;

typedef vector<string> svec;
typedef vector<vector<string>> smat;
const ll infll = (1LL << 60) - 1;
const int inf = (1 << 30) - 1;
const ll MOD = 1000000007;

ll gcd(ll x, ll y) {
  ll r = x % y;
  if (r == 0)
    return y;
  else
    return gcd(y, r);
}

ll lcm(ll x, ll y) { return x * y / gcd(x, y); }

lvec mfactor(ll n) {
  bvec ip(n, true);
  lvec mf(n, -1);
  ip[0] = false;
  ip[1] = false;
  mf[0] = 0;
  mf[1] = 1;
  REP(i, n) {
    if (ip[i]) {
      mf[i] = i;
      for (ll j = i * i; j < n; j += i) {
        ip[j] = false;
        if (mf[j] == -1)
          mf[j] = i;
      }
    }
  }
  return mf;
}

palivec get_prime(ll n, const lvec &mf) {
  palivec plist;
  while (n != 1) {
    int cnt = 0;
    ll m = mf[n];
    while (mf[n] == m) {
      cnt++;
      n /= m;
    }
    plist.pb(pali(m, cnt));
  }
  return plist;
}

void COMinit(int m, lvec &fac, lvec &finv) {
  lvec inv(m);
  fac[0] = fac[1] = 1;
  finv[0] = finv[1] = 1;
  inv[1] = 1;
  for (int i = 2; i < m; i++) {
    fac[i] = fac[i - 1] * i % MOD;
    inv[i] = MOD - inv[MOD % i] * (MOD / i) % MOD;
    finv[i] = finv[i - 1] * inv[i] % MOD;
  }
}

ll pow_mod(ll a, ll n) {
  ll x = 1;
  while (n > 0) {
    if (n & 1) {
      x = x * a % MOD;
    }
    a = a * a % MOD;
    n >>= 1;
  }
  return x;
}

ll pow_mod2(ll a, ll n) {
  ll x = 1;
  while (n > 0) {
    if (n & 1) {
      x = x * a;
    }
    a = a * a;
    n >>= 1;
  }
  return x;
}

ll COM(int n, int k, const lvec &fac, const lvec &finv) {
  if (n < k)
    return 0;
  if (n < 0 || k < 0)
    return 0;
  return (fac[n] * (finv[k] * finv[n - k] % MOD)) % MOD;
}

ll modinv(ll a, ll m) {
  ll b = m, u = 1, v = 0;
  while (b) {
    ll t = a / b;
    a -= t * b;
    swap(a, b);
    u -= t * v;
    swap(u, v);
  }
  u %= m;
  if (u < 0)
    u += m;
  return u;
}

// union by size + path having
class UnionFind {
public:
  vector<ll> par;
  vector<ll> siz;

  // Constructor
  UnionFind(ll sz_) : par(sz_), siz(sz_, 1LL) {
    for (ll i = 0; i < sz_; ++i)
      par[i] = i;
  }
  void init(ll sz_) {
    par.resize(sz_);
    siz.assign(sz_, 1LL);
    for (ll i = 0; i < sz_; ++i)
      par[i] = i;
  }

  // Member Function
  // Find
  ll root(ll x) {
    while (par[x] != x) {
      x = par[x] = par[par[x]];
    }
    return x;
  }

  // Union(Unite, Merge)
  bool merge(ll x, ll y) {
    x = root(x);
    y = root(y);
    if (x == y)
      return false;
    if (siz[x] < siz[y])
      swap(x, y);
    siz[x] += siz[y];
    par[y] = x;
    return true;
  }

  bool issame(ll x, ll y) { return root(x) == root(y); }

  ll size(ll x) { return siz[root(x)]; }
};

int main() {
  cin.tie(0);
  ios::sync_with_stdio(false);
  ll s;
  cin >> s;
  ll n = s / 3 + 1;
  lmat dp(n, lvec(s + 1, 0));
  if (s < 3) {
    cout << 0 << endl;
    return 0;
  }
  for (int i = 3; i < s + 1; i++) {
    dp[0][i] = 1;
  }
  ll ans = 1;
  for (int i = 1; i < n; i++) {
    for (int j = 3 * (i + 1); j < s + 1; j++) {
      for (int k = 3; k <= j; k++) {
        dp[i][j] += dp[i - 1][j - k];
        dp[i][j] %= MOD;
      }
    }
    ans += dp[i][s];
    ans %= MOD;
  }
  cout << ans << endl;
}

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
#define pa pair<int, int>
#define pal pair<long long, long long>
#define pali pair<long long, int>
#define pad pair<double, double>
#define pb push_back
#define mp make_pair
#define COUT(v)                                                                \\
  for (int64_t i = 0; i < (v).size(); ++i) {                                   \\
    cout << v.at(i) << endl;                                                   \\
  }
#define REP(i, n) for (int64_t i = 0; i < n; ++i)
#define FOR(i, r, n) for (int64_t i = (r); i < n; ++i)
#define VIN(v)                                                                 \\
  for (int64_t i = 0; i < (v).size(); ++i) {                                   \\
    cin >> (v).at(i);                                                          \\
  }

typedef vector<bool> bvec;
typedef vector<int> ivec;
typedef vector<long long> lvec;
typedef vector<double> dvec;
typedef vector<pa> pavec;
typedef vector<pali> palivec;
typedef vector<pal> palvec;

typedef vector<vector<bool>> bmat;
typedef vector<vector<int>> imat;
typedef vector<vector<long long>> lmat;

typedef vector<string> svec;
typedef vector<vector<string>> smat;
const ll infll = (1LL << 60) - 1;
const int inf = (1 << 30) - 1;
const ll MOD = 1000000007;

ll gcd(ll x, ll y) {
  ll r = x % y;
  if (r == 0)
    return y;
  else
    return gcd(y, r);
}

ll lcm(ll x, ll y) { return x * y / gcd(x, y); }

lvec mfactor(ll n) {
  bvec ip(n, true);
  lvec mf(n, -1);
  ip[0] = false;
  ip[1] = false;
  mf[0] = 0;
  mf[1] = 1;
  REP(i, n) {
    if (ip[i]) {
      mf[i] = i;
      for (ll j = i * i; j < n; j += i) {
        ip[j] = false;
        if (mf[j] == -1)
          mf[j] = i;
      }
    }
  }
  return mf;
}

palivec get_prime(ll n, const lvec &mf) {
  palivec plist;
  while (n != 1) {
    int cnt = 0;
    ll m = mf[n];
    while (mf[n] == m) {
      cnt++;
      n /= m;
    }
    plist.pb(pali(m, cnt));
  }
  return plist;
}

void COMinit(int m, lvec &fac, lvec &finv) {
  lvec inv(m);
  fac[0] = fac[1] = 1;
  finv[0] = finv[1] = 1;
  inv[1] = 1;
  for (int i = 2; i < m; i++) {
    fac[i] = fac[i - 1] * i % MOD;
    inv[i] = MOD - inv[MOD % i] * (MOD / i) % MOD;
    finv[i] = finv[i - 1] * inv[i] % MOD;
  }
}

ll pow_mod(ll a, ll n) {
  ll x = 1;
  while (n > 0) {
    if (n & 1) {
      x = x * a % MOD;
    }
    a = a * a % MOD;
    n >>= 1;
  }
  return x;
}

ll pow_mod2(ll a, ll n) {
  ll x = 1;
  while (n > 0) {
    if (n & 1) {
      x = x * a;
    }
    a = a * a;
    n >>= 1;
  }
  return x;
}

ll COM(int n, int k, const lvec &fac, const lvec &finv) {
  if (n < k)
    return 0;
  if (n < 0 || k < 0)
    return 0;
  return (fac[n] * (finv[k] * finv[n - k] % MOD)) % MOD;
}

ll modinv(ll a, ll m) {
  ll b = m, u = 1, v = 0;
  while (b) {
    ll t = a / b;
    a -= t * b;
    swap(a, b);
    u -= t * v;
    swap(u, v);
  }
  u %= m;
  if (u < 0)
    u += m;
  return u;
}

// union by size + path having
class UnionFind {
public:
  vector<ll> par;
  vector<ll> siz;

  // Constructor
  UnionFind(ll sz_) : par(sz_), siz(sz_, 1LL) {
    for (ll i = 0; i < sz_; ++i)
      par[i] = i;
  }
  void init(ll sz_) {
    par.resize(sz_);
    siz.assign(sz_, 1LL);
    for (ll i = 0; i < sz_; ++i)
      par[i] = i;
  }

  // Member Function
  // Find
  ll root(ll x) {
    while (par[x] != x) {
      x = par[x] = par[par[x]];
    }
    return x;
  }

  // Union(Unite, Merge)
  bool merge(ll x, ll y) {
    x = root(x);
    y = root(y);
    if (x == y)
      return false;
    if (siz[x] < siz[y])
      swap(x, y);
    siz[x] += siz[y];
    par[y] = x;
    return true;
  }

  bool issame(ll x, ll y) { return root(x) == root(y); }

  ll size(ll x) { return siz[root(x)]; }
};

int main() {
  cin.tie(0);
  ios::sync_with_stdio(false);
  ll s;
  cin >> s;
  ll n = s / 3 + 1;
  lmat dp(n, lvec(s + 1, 0));
  if (s < 3) {
    cout << 0 << endl;
    return 0;
  }
  for (int i = 3; i < s + 1; i++) {
    dp[0][i] = 1;
  }
  ll ans = 1;
  for (int i = 1; i < n; i++) {
    for (int j = 3 * (i + 1); j < s + 1; j++) {
      dp[i][j] = dp[i][j - 1] + dp[i - 1][j - 3];
      dp[i][j] %= MOD;
      /*
      for (int k = 3; k <= j; k++)
      {
          dp[i][j] += dp[i - 1][j - k];
          dp[i][j] %= MOD;
      }
      */
    }
    ans += dp[i][s];
    ans %= MOD;
  }
  cout << ans << endl;
}


#include <bits/stdc++.h>
using namespace std;

#define vvi vector<vector<int>>
#define ld long double
#define mod 1000000007
#define ff first
#define ss second
#define int long long
#define pb push_back
#define mp make_pair
#define pii pair<int, int>
#define vpii vector<pair<int, int>>
#define fr(i, a, b) for (int i = a; i < b; i += 1)
#define all(x) x.begin(), x.end()
#define sz(a) (int)(a.size())
#define vi vector<int>
#define mii map<int, int>
#define pqb priority_queue<int>
#define pqs priority_queue<int, vi, greater<int>>
#define setbits(x) __builtin_popcountll(x)
#define zrobits(x) __builtin_ctzll(x)
#define inf 1e18
#define ps(x, y) fixed << setprecision(y) << x
#define mk(arr, n, type) type *arr = new type[n];
#define w(x)                                                                   \\
  int x;                                                                       \\
  cin >> x;                                                                    \\
  while (x--)
#define pw(b, p) pow(b, p) + 0.1
#define input(a)                                                               \\
  for (auto it = a.begin(); it != a.end(); it++) {                             \\
    int value;                                                                 \\
    cin >> value;                                                              \\
    *it = value;                                                               \\
  }
// #define print(a)        for(auto it = a.begin() ; it != a.end() ; it++){ cout
// << *it << " " ;}cout << '\\n';
#define SS stringstream
#define db(...) __f(#__VA_ARGS__, __VA_ARGS__)

template <typename Arg1> void __f(const char *name, Arg1 &&arg1) {
  cerr << name << " : " << arg1 << '\\n';
}
template <typename Arg1, typename... Args>
void __f(const char *names, Arg1 &&arg1, Args &&...args) {
  const char *comma = strchr(names + 1, ',');
  cerr.write(names, comma - names) << " : " << arg1 << " | ";
  __f(comma + 1, args...);
}

const int dirx[4] = {0, 0, -1, 1};
const int diry[4] = {-1, 1, 0, 0};

// 0 -> l, 1 - > r, 2 -> u , 3 -> down
void FASTIO() {
  ios_base::sync_with_stdio(0);
  cin.tie(0);
  cout.tie(0);
#ifndef ONLINE_JUDGE
  freopen("input.txt", "r", stdin);
  freopen("output.txt", "w", stdout);
#endif
}

const int mxN = 2e3 + 10;
int n;
int dp[mxN][mxN];
// 0 -> none, 1-> 0 only, 2-> 9only, 3->0,9 only

void test_case() {
  cin >> n;

  for (int i = 0; i <= n; i++) {
    for (int j = 1; j <= n; j++) {
      dp[i][j] = 0;
    }
  }

  dp[0][0] = 1;

  for (int i = 1; i <= n; i++) {
    for (int j = 3; j <= n; j++) {
      for (int k = 3; k <= n; k++) {
        if (j - k >= 0)
          dp[i][j] = (dp[i][j] + dp[i - 1][j - k]) % mod;
      }
    }
  }

  int ans = 0;
  for (int i = 1; i <= n; i++)
    ans = (ans + dp[i][n]) % mod;

  cout << ans;
}

int32_t main() {
  FASTIO();

  int t;
  t = 1;
  // cin >> t;

  for (int i = 1; i <= t; i++) {
    // cout << "Case #" << i << ": ";
    test_case();
  }
  return 0;
}

#include <bits/stdc++.h>
using namespace std;

#define vvi vector<vector<int>>
#define ld long double
#define mod 1000000007
#define ff first
#define ss second
#define int long long
#define pb push_back
#define mp make_pair
#define pii pair<int, int>
#define vpii vector<pair<int, int>>
#define fr(i, a, b) for (int i = a; i < b; i += 1)
#define all(x) x.begin(), x.end()
#define sz(a) (int)(a.size())
#define vi vector<int>
#define mii map<int, int>
#define pqb priority_queue<int>
#define pqs priority_queue<int, vi, greater<int>>
#define setbits(x) __builtin_popcountll(x)
#define zrobits(x) __builtin_ctzll(x)
#define inf 1e18
#define ps(x, y) fixed << setprecision(y) << x
#define mk(arr, n, type) type *arr = new type[n];
#define w(x)                                                                   \\
  int x;                                                                       \\
  cin >> x;                                                                    \\
  while (x--)
#define pw(b, p) pow(b, p) + 0.1
#define input(a)                                                               \\
  for (auto it = a.begin(); it != a.end(); it++) {                             \\
    int value;                                                                 \\
    cin >> value;                                                              \\
    *it = value;                                                               \\
  }
// #define print(a)        for(auto it = a.begin() ; it != a.end() ; it++){ cout
// << *it << " " ;}cout << '\\n';
#define SS stringstream
#define db(...) __f(#__VA_ARGS__, __VA_ARGS__)

template <typename Arg1> void __f(const char *name, Arg1 &&arg1) {
  cerr << name << " : " << arg1 << '\\n';
}
template <typename Arg1, typename... Args>
void __f(const char *names, Arg1 &&arg1, Args &&...args) {
  const char *comma = strchr(names + 1, ',');
  cerr.write(names, comma - names) << " : " << arg1 << " | ";
  __f(comma + 1, args...);
}

const int dirx[4] = {0, 0, -1, 1};
const int diry[4] = {-1, 1, 0, 0};

// 0 -> l, 1 - > r, 2 -> u , 3 -> down
void FASTIO() {
  ios_base::sync_with_stdio(0);
  cin.tie(0);
  cout.tie(0);
#ifndef ONLINE_JUDGE
  freopen("input.txt", "r", stdin);
  freopen("output.txt", "w", stdout);
#endif
}

const int mxN = 2e3 + 10;
int n;
int dp[mxN][mxN];
// 0 -> none, 1-> 0 only, 2-> 9only, 3->0,9 only

void test_case() {
  cin >> n;

  for (int i = 0; i <= n; i++) {
    for (int j = 1; j <= n; j++) {
      dp[i][j] = 0;
    }
  }

  dp[0][0] = 1;

  for (int j = 3; j <= n; j++)
    dp[1][j] = 1;

  for (int i = 2; i <= n; i++) {
    int sum = 0;
    for (int j = 0; j <= n - 3; j++)
      sum = (sum + dp[i - 1][j]);

    for (int j = n; j >= 3; j--) {
      dp[i][j] = sum;
      sum -= dp[i - 1][j - 3];
    }

    for (int j = n; j >= 0; j--) {
      dp[i][j] %= mod;
    }
  }

  int ans = 0;
  for (int i = 1; i <= n; i++)
    ans = (ans + dp[i][n]) % mod;

  // for(int i = )

  cout << ans;
}

int32_t main() {
  FASTIO();

  int t;
  t = 1;
  // cin >> t;

  for (int i = 1; i <= t; i++) {
    // cout << "Case #" << i << ": ";
    test_case();
  }
  return 0;
}


#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define M 1000000007
ll n;
ll Dp[2001];
long long mod(long long x) { return ((x % M + M) % M); }
long long add(long long a, long long b) { return mod(mod(a) + mod(b)); }

ll solve(ll s) {
  if (s == 1 || s == 2)
    return 0;
  if (s == 3 || s == 4 || s == 5 || s == 0)
    return 1;
  if (Dp[s] == -1) {
    Dp[s] = 0;
    for (int j = 3; j <= n; j++) {
      Dp[s] = add(Dp[s], solve(s - j));
    }
  }
  // else Dp[s]++;
  return Dp[s];
}

int main() {
  ios_base::sync_with_stdio(false);
  cin.tie(NULL);
  memset(Dp, -1, sizeof(Dp));
  cin >> n;
  cout << solve(n); //<<endl;
  // for(int i=0;i<=n;i++)
  // cout<<Dp[i]<<" ";
  return 0;
}

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define M 1000000007
ll n;
ll Dp[2001];
long long mod(long long x) { return ((x % M + M) % M); }
long long add(long long a, long long b) { return mod(mod(a) + mod(b)); }

ll solve(ll s) {
  if (s == 1 || s == 2)
    return 0LL;
  if (s == 3 || s == 4 || s == 5 || s == 0)
    return 1LL;
  if (Dp[s] == -1) {
    Dp[s] = 0;
    for (int j = 3; j <= n; j++) {
      if (s - j >= 0)
        Dp[s] = add(Dp[s], solve(s - j));
    }
  }
  // else Dp[s]++;
  return Dp[s];
}

int main() {
  ios_base::sync_with_stdio(false);
  cin.tie(NULL);
  memset(Dp, -1, sizeof(Dp));
  cin >> n;
  cout << solve(n); //<<endl;
  // for(int i=0;i<=n;i++)
  // cout<<Dp[i]<<" ";
  return 0;
}


#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < n; i++)
#define FOR(i, start, end) for (int i = start; i <= end; i++)
const int INF = 1001001001;
#define all(a) a.begin(), a.end()
#define rall(a) a.rbegin(), a.rend()
#define Sort(a) sort(a.begin(), a.end())
#define Rort(a) sort(a.rbegin(), a.rend())
typedef long long ll;
const ll MOD = 1000000007;
using namespace std;
template <class T> inline bool chmax(T &a, T b) {
  if (a < b) {
    a = b;
    return 1;
  }
  return 0;
}
template <class T> inline bool chmin(T &a, T b) {
  if (a > b) {
    a = b;
    return 1;
  }
  return 0;
}
template <class T> auto MAX(const T &a) {
  return *max_element(a.begin(), a.end());
}
template <class T> auto MIN(const T &a) {
  return *min_element(a.begin(), a.end());
}
template <class T, class U> U SUM(const T &a, const U &v) {
  return accumulate(a.begin(), a.end(), v);
}
template <class T, class U> U COUNT(const T &a, const U &v) {
  return count(a.begin(), a.end(), v);
}
template <class T, class U> int LOWER(const T &a, const U &v) {
  return lower_bound(a.begin(), a.end(), v) - a.begin();
}
template <class T, class U> int UPPER(const T &a, const U &v) {
  return upper_bound(a.begin(), a.end(), v) - a.begin();
}
int GCD(int a, int b) { return b ? GCD(b, a % b) : a; }
int LCM(int a, int b) {
  int g = GCD(a, b);
  return a / g * b;
}
typedef long double ld;
typedef unsigned long long int ull;
typedef pair<int, int> P;
typedef vector<int> vi;
typedef vector<char> vc;
typedef vector<bool> vb;
typedef vector<double> vd;
typedef vector<string> vs;
typedef vector<ll> vll;
typedef vector<pair<int, int>> vpii;
typedef vector<pair<ll, ll>> vpll;
typedef vector<vi> vvi;
typedef vector<vvi> vvvi;
typedef vector<vc> vvc;
typedef vector<vs> vvs;
typedef vector<vll> vvll;
typedef map<int, int> mii;
typedef set<int> si;
//---------------------------------------------------------------------------------------------------

int dp[1000][2004];

int main(void) {
  // Your code here!
  int s;
  cin >> s;
  memset(dp, 0, sizeof(dp));
  FOR(i, 3, 2000) dp[0][i] = 1;
  FOR(i, 1, s / 3 + 1) {
    FOR(j, 3, 2000) {
      FOR(k, 3, j - 3) {
        dp[i][j] += dp[i - 1][j - k];
        dp[i][j] %= MOD;
      }
    }
  }
  ll ans = 0;
  rep(i, 668) {
    ans += dp[i][s];
    ans %= MOD;
  }
  cout << ans << endl;
}

#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < n; i++)
#define FOR(i, start, end) for (int i = start; i <= end; i++)
const int INF = 1001001001;
#define all(a) a.begin(), a.end()
#define rall(a) a.rbegin(), a.rend()
#define Sort(a) sort(a.begin(), a.end())
#define Rort(a) sort(a.rbegin(), a.rend())
typedef long long ll;
const ll MOD = 1000000007;
using namespace std;
template <class T> inline bool chmax(T &a, T b) {
  if (a < b) {
    a = b;
    return 1;
  }
  return 0;
}
template <class T> inline bool chmin(T &a, T b) {
  if (a > b) {
    a = b;
    return 1;
  }
  return 0;
}
template <class T> auto MAX(const T &a) {
  return *max_element(a.begin(), a.end());
}
template <class T> auto MIN(const T &a) {
  return *min_element(a.begin(), a.end());
}
template <class T, class U> U SUM(const T &a, const U &v) {
  return accumulate(a.begin(), a.end(), v);
}
template <class T, class U> U COUNT(const T &a, const U &v) {
  return count(a.begin(), a.end(), v);
}
template <class T, class U> int LOWER(const T &a, const U &v) {
  return lower_bound(a.begin(), a.end(), v) - a.begin();
}
template <class T, class U> int UPPER(const T &a, const U &v) {
  return upper_bound(a.begin(), a.end(), v) - a.begin();
}
int GCD(int a, int b) { return b ? GCD(b, a % b) : a; }
int LCM(int a, int b) {
  int g = GCD(a, b);
  return a / g * b;
}
typedef long double ld;
typedef unsigned long long int ull;
typedef pair<int, int> P;
typedef vector<int> vi;
typedef vector<char> vc;
typedef vector<bool> vb;
typedef vector<double> vd;
typedef vector<string> vs;
typedef vector<ll> vll;
typedef vector<pair<int, int>> vpii;
typedef vector<pair<ll, ll>> vpll;
typedef vector<vi> vvi;
typedef vector<vvi> vvvi;
typedef vector<vc> vvc;
typedef vector<vs> vvs;
typedef vector<vll> vvll;
typedef map<int, int> mii;
typedef set<int> si;
//---------------------------------------------------------------------------------------------------

int dp[1000][2004];

int main(void) {
  // Your code here!
  int s;
  cin >> s;
  memset(dp, 0, sizeof(dp));
  FOR(i, 3, 2000) dp[0][i] = 1;
  FOR(i, 1, s / 3 + 1) {
    FOR(j, 3, 2000) {
      dp[i][j] = dp[i][j - 1] + dp[i - 1][j - 3];
      dp[i][j] %= MOD;
      // FOR(k,3,j-3){
      //     dp[i][j] += dp[i-1][j-k];
      //     dp[i][j] %= MOD;
      // }
    }
  }
  ll ans = 0;
  rep(i, 668) {
    ans += dp[i][s];
    ans %= MOD;
  }
  cout << ans << endl;
}


#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define pb push_back
#define mp make_pair
#define ff first
#define ss second
#define db double
#define pll pair<ll, ll>
#define pdb pair<db, db>
#define ldb long double
#define clr(x) memset(x, 0, sizeof(x))
#define count_bit(x) __builtin_popcount(x)
#define debug(x) cout << #x << " :: " << x << endl;
#define debug2(x, y)                                                           \\
  cout << #x << " :: " << x << "\\t" << #y << " :: " << y << endl;
#define debug3(x, y, z)                                                        \\
  cout << #x << " :: " << x << "\\t" << #y << " :: " << y << "\\t" << #z         \\
       << " :: " << z << endl;
const int size1 = 1e5 + 7;
const int size2 = 1e4;
const ll mod = 1e9 + 7;

// ll fact[size1];

ll pw(ll x, ll y, ll md) {
  if (y == 0)
    return 1;
  ll p = pw(x, y / 2, md);
  p = (p * p) % md;
  if (y % 2 == 1)
    p = (p * x) % md;
  return p;
}
// ll gcd(ll a,ll b)
// {
//  if(b==0)return a;
//  a = a%b;
//  return gcd(b,a);
// }
// ll inverse(ll x,ll mod)
// {
//     return pw(x,mod-2,mod);
// }
// ll ncr(ll n,ll r,ll mod)
// {
//     ll num = fact[n];
//     ll den = (fact[r] * fact[n-r])%mod;
//     den = inverse(den,mod);

//     ll ans = (num*den)%mod;
//     return ans;
// }
// vector<ll> adj1[size1];
// vector<ll> adj[size1];
// ll d[size1];
// ll n,m;
// void dikstra(ll s)
// {
//     for(ll i=1;i<=n;i++)d[i]=1e9;
//     d[s] = 0;
//     priority_queue<pll, vector<pll>, greater<pll>> q;
//     q.push({0, s});
//     while(!q.empty())
//     {
//         ll v = q.top().ss;
//         ll d_v = q.top().ff;
//         q.pop();
//         if(d_v!=d[v])continue;
//         for(auto to:adj1[v])
//         {
//             ll len = 1;
//             if(d[v] + len < d[to])
//             {
//                 d[to] = d[v]+len;
//                 q.push({d[to],to});
//             }
//         }
//     }
// }

// ll smallestPrimeFactor[size1];

// void seive(){
//     clr(smallestPrimeFactor);

//     for(ll i=2;i<size1;i++){
//         if(smallestPrimeFactor[i]!=0)continue;
//         smallestPrimeFactor[i] = i;
//         for(ll j=2*i;j<size1;j+=i){
//             smallestPrimeFactor[j]=i;
//         }
//     }
// }

int main() {
// cout<<setprecision(12)<<fixed;
#ifndef ONLINE_JUDGE
  freopen("input.txt", "r", stdin);
  freopen("output.txt", "w", stdout);
#endif
  ios_base::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);

  ll T;
  // cin>>T;
  T = 1;
  while (T--) {
    // cout<<"Case #"<<cas<<": ";cas++;
    ll S;
    cin >> S;

    ll mxLen = S / 3 + 1;
    ll dp[mxLen + 1][S + 1];

    clr(dp);
    for (ll j = 3; j <= S; j++)
      dp[1][j] = 1;

    for (ll i = 2; i <= mxLen; i++) {
      for (ll j = i * 3; j <= S; j++) {
        for (ll k = j - 3; k >= 0; k--) {
          dp[i][j] = (dp[i][j] + dp[i - 1][k]) % mod;
        }
      }
    }

    ll ans = 0;
    for (ll i = 1; i <= mxLen; i++)
      ans = (ans + dp[i][S]) % mod;

    cout << ans << endl;
  }
}

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define pb push_back
#define mp make_pair
#define ff first
#define ss second
#define db double
#define pll pair<ll, ll>
#define pdb pair<db, db>
#define ldb long double
#define clr(x) memset(x, 0, sizeof(x))
#define count_bit(x) __builtin_popcount(x)
#define debug(x) cout << #x << " :: " << x << endl;
#define debug2(x, y)                                                           \\
  cout << #x << " :: " << x << "\\t" << #y << " :: " << y << endl;
#define debug3(x, y, z)                                                        \\
  cout << #x << " :: " << x << "\\t" << #y << " :: " << y << "\\t" << #z         \\
       << " :: " << z << endl;
const int size1 = 1e5 + 7;
const int size2 = 1e4;
const ll mod = 1e9 + 7;

// ll fact[size1];

// ll pw(ll x,ll y,ll md)
// {
//     if(y==0)return 1;
//     ll p =pw(x,y/2,md);
//     p = (p*p)%md;
//     if(y%2==1)p = (p*x)%md;
//     return p;
// }
// ll gcd(ll a,ll b)
// {
//  if(b==0)return a;
//  a = a%b;
//  return gcd(b,a);
// }
// ll inverse(ll x,ll mod)
// {
//     return pw(x,mod-2,mod);
// }
// ll ncr(ll n,ll r,ll mod)
// {
//     ll num = fact[n];
//     ll den = (fact[r] * fact[n-r])%mod;
//     den = inverse(den,mod);

//     ll ans = (num*den)%mod;
//     return ans;
// }
// vector<ll> adj1[size1];
// vector<ll> adj[size1];
// ll d[size1];
// ll n,m;
// void dikstra(ll s)
// {
//     for(ll i=1;i<=n;i++)d[i]=1e9;
//     d[s] = 0;
//     priority_queue<pll, vector<pll>, greater<pll>> q;
//     q.push({0, s});
//     while(!q.empty())
//     {
//         ll v = q.top().ss;
//         ll d_v = q.top().ff;
//         q.pop();
//         if(d_v!=d[v])continue;
//         for(auto to:adj1[v])
//         {
//             ll len = 1;
//             if(d[v] + len < d[to])
//             {
//                 d[to] = d[v]+len;
//                 q.push({d[to],to});
//             }
//         }
//     }
// }

// ll smallestPrimeFactor[size1];

// void seive(){
//     clr(smallestPrimeFactor);

//     for(ll i=2;i<size1;i++){
//         if(smallestPrimeFactor[i]!=0)continue;
//         smallestPrimeFactor[i] = i;
//         for(ll j=2*i;j<size1;j+=i){
//             smallestPrimeFactor[j]=i;
//         }
//     }
// }
ll sum[2005][2005];
ll dp[2005][2005];
int main() {
// cout<<setprecision(12)<<fixed;
#ifndef ONLINE_JUDGE
  freopen("input.txt", "r", stdin);
  freopen("output.txt", "w", stdout);
#endif
  ios_base::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);

  ll T;
  // cin>>T;
  T = 1;
  while (T--) {
    // cout<<"Case #"<<cas<<": ";cas++;
    ll S;
    cin >> S;

    ll mxLen = S / 3 + 1;

    clr(dp);
    clr(sum);
    for (ll j = 3; j <= S; j++) {
      dp[1][j] = 1;
      sum[1][j] = (sum[1][j - 1] + dp[1][j]) % mod;
    }
    for (ll i = 2; i <= mxLen; i++) {
      for (ll j = 3; j <= S; j++) {

        dp[i][j] = (dp[i][j] + sum[i - 1][j - 3]) % mod;
        sum[i][j] = (sum[i][j - 1] + dp[i][j]) % mod;
      }
    }

    ll ans = 0;
    for (ll i = 1; i <= mxLen; i++)
      ans = (ans + dp[i][S]) % mod;

    cout << ans << endl;
  }
}


#include <iostream>
// #include<atcoder/all>

using namespace std;
// using namespace atcoder;

#pragma GCC target("avx2")
#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")

int main() {
  ios::sync_with_stdio(false);
  std::cin.tie(nullptr);

  long long S;
  const long long mod = 1000000007;
  cin >> S;
  long long dp[S + 10][S + 10];
  for (int i = 0; i < S + 10; i++) {
    for (int j = 0; j < S + 10; j++) {
      dp[i][j] = 0;
    }
  }
  dp[0][0] = 1;
  long long to = S / 3 + 1;
  for (int j = 0; j < to; j++) {
    for (int i = j; i < S; i++) {
      for (int k = 3; k <= S - i; k++) {
        dp[i + k][j + 1] += dp[i][j] % mod;
      }
    }
  }
  long long sum = 0;
  for (int i = 0; i <= S; i++) {
    sum += dp[S][i];
    sum %= mod;
    // cout<<sum<<endl;
  }
  cout << sum << endl;
}

#include <iostream>
// #include<atcoder/all>

using namespace std;
// using namespace atcoder;

#pragma GCC target("avx2")
#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")

int main() {
  ios::sync_with_stdio(false);
  std::cin.tie(nullptr);

  long long S;
  const long long mod = 1000000007;
  cin >> S;
  long long dp[S + 10];
  for (int i = 0; i < S + 10; i++) {
    dp[i] = 0;
  }
  dp[0] = 1;
  for (int i = 0; i < S; i++) {
    for (int k = 3; k <= S - i; k++) {
      dp[i + k] += dp[i] % mod;
    }
  }

  cout << dp[S] % mod << endl;
}


#include <iostream>
#include <vector>

typedef long long ll;
const ll m = 1e9 + 7;

int main(int argc, char **argv) {
  int S;
  std::cin >> S;

  std::vector<ll> A(S + 1, 0);

  A[3] = 1;

  for (int i = 4; i < S + 1; i++) {
    A[i] = A[i - 3] + A[i - 1];
    A[i] %= m;
  }

  std::cout << A[S] << std::endl;
}

#include <iostream>
#include <vector>

typedef long long ll;
const ll m = 1e9 + 7;

int main(int argc, char **argv) {
  int S;
  std::cin >> S;

  std::vector<ll> A(2001, 0);

  A[3] = 1;

  for (int i = 4; i < S + 1; i++) {
    A[i] = A[i - 3] + A[i - 1];
    A[i] %= m;
  }

  std::cout << A[S] << std::endl;
}


#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace std;
using namespace __gnu_pbds;
#define ordered_set                                                            \\
  tree<int, null_type, less<int>, rb_tree_tag,                                 \\
       tree_order_statistics_node_update>
#define ll long long
#define FASTIO                                                                 \\
  ios_base::sync_with_stdio(0);                                                \\
  cin.tie(0);                                                                  \\
  cout.tie(0);
#define inf 1e9
#define ff first
#define ss second
#define lb lower_bound
#define ub upper_bound
#define bs binary_search
#define mod 1000000007
#define pb push_back
#define all(s) s.begin(), s.end()
#define pie 3.14159265358979323846
#define fr(i, a, b) for (ll i = a; i < b; i++)
#define frr(i, a, b) for (ll i = b - 1; i >= a; i--)
#define gcd __gcd
#define con continue
#define pii pair<ll, ll>
const ll N = 1e5 + 6;
ll n, a, b, x;
ll par[N];
void make_par() {
  for (ll i = 0; i < N; i++)
    par[i] = i;
}
ll find_par(ll u) {
  if (par[u] == u)
    return u;
  return par[u] = find_par(par[u]);
}
void union_par(ll a, ll b) {
  a = find_par(a);
  b = find_par(b);
  par[a] = b;
  return;
}
signed main() {
  FASTIO;
  ll tt = 1;
  // cin>>tt;
  while (tt--) {
    make_par();
    ll n, m;
    cin >> m >> n;
    for (ll i = 0; i < n; i++) {
      cin >> x;
      if (x == 1) {
        cin >> a >> b;
        a = find_par(a);
        b = find_par(b);
        if (a == b)
          cout << "1\\n";
        else
          cout << "0\\n";
        con;
      }
      cin >> a >> b;
      union_par(a, b);
    }
  }
}

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace std;
using namespace __gnu_pbds;
#define ordered_set                                                            \\
  tree<int, null_type, less<int>, rb_tree_tag,                                 \\
       tree_order_statistics_node_update>
#define ll long long
#define FASTIO                                                                 \\
  ios_base::sync_with_stdio(0);                                                \\
  cin.tie(0);                                                                  \\
  cout.tie(0);
#define inf 1e9
#define ff first
#define ss second
#define lb lower_bound
#define ub upper_bound
#define bs binary_search
#define mod 1000000007
#define pb push_back
#define all(s) s.begin(), s.end()
#define pie 3.14159265358979323846
#define fr(i, a, b) for (ll i = a; i < b; i++)
#define frr(i, a, b) for (ll i = b - 1; i >= a; i--)
#define gcd __gcd
#define con continue
#define pii pair<ll, ll>
const ll N = 4e5 + 6;
ll n, a, b, x;
ll par[N];
void make_par() {
  for (ll i = 0; i < N; i++)
    par[i] = i;
}
ll find_par(ll u) {
  if (par[u] == u)
    return u;
  return par[u] = find_par(par[u]);
}
void union_par(ll a, ll b) {
  a = find_par(a);
  b = find_par(b);
  par[a] = b;
  return;
}
signed main() {
  FASTIO;
  ll tt = 1;
  // cin>>tt;
  while (tt--) {
    make_par();
    ll n, m;
    cin >> m >> n;
    for (ll i = 0; i < n; i++) {
      cin >> x;
      if (x == 1) {
        cin >> a >> b;
        a = find_par(a);
        b = find_par(b);
        if (a == b)
          cout << "1\\n";
        else
          cout << "0\\n";
        con;
      }
      cin >> a >> b;
      union_par(a, b);
    }
  }
}


// #pragma GCC optimize("Ofast")
// #pragma GCC target("avx,avx2,fma")
// #pragma GCC optimization ("unroll-loops")

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
using namespace __gnu_pbds;
using namespace std;

#define fo(i, n) for (int i = 0; i < n; i++)
#define nl "\\n"
#define ff first
#define ss second
#define int long long
#define pb push_back
#define mp make_pair
#define vec(x) vector<x>
#define matrix(x) vector<vector<x>>
#define sz(x) (int)x.size()
#define mem(a, b) memset(a, b, sizeof a)
#define vii vector<pair<int, int>>
#define pii pair<int, int>
#define vi vector<int>
#define mii map<int, int>
#define uii unordered_map<int, int, custom_hash>
#define pqb priority_queue<int>
#define pqs priority_queue<int, vi, greater<int>>
#define gcd(a, b) __gcd(a, b)
#define lcm(a, b) (a * (b / gcd(a, b)))
#define setbits(x) __builtin_popcountll(x)
#define zrobits(x) __builtin_ctzll(x)
#define mod 1000000007
#define MOD 998244353
#define inf 1e18
#define ps(x, y) fixed << setprecision(y) << x
#define mk(arr, n, type) type *arr = new type[n];
#define w(x)                                                                   \\
  int x;                                                                       \\
  cin >> x;                                                                    \\
  while (x--)
#define all(v) v.begin(), v.end()
#define rep(i, begin, end)                                                     \\
  for (__typeof(end) i = (begin) - ((begin) > (end));                          \\
       i != (end) - ((begin) > (end)); i += 1 - 2 * ((begin) > (end)))
#define len(s) s.length()

#define watch(x) cout << #x << " = " << x << endl

#define deb(...) cerr << "[" << #__VA_ARGS__ << "] : [", DBG(__VA_ARGS__)
void DBG() { cerr << "]\\n"; }
template <typename T, typename... Args> void DBG(T first, Args... args) {
  cerr << first;
  if (sizeof...(args))
    cerr << ", ";
  DBG(args...);
}

mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());

typedef tree<int, null_type, less<int>, rb_tree_tag,
             tree_order_statistics_node_update>
    pbds; // for storing unique elements
typedef tree<int, null_type, less_equal<int>, rb_tree_tag,
             tree_order_statistics_node_update>
    ordered_set; // for repeating elements

int power(int a, int b, int m = mod) {
  int ans = 1;
  while (b > 0) {
    if (b & 1)
      ans = (ans * a) % m;
    a = (a * a) % m;
    b >>= 1;
  }
  return ans;
}

void babuBhaiya() {
#ifndef ONLINE_JUDGE
  freopen("input.txt", "r", stdin);
  freopen("output.txt", "w", stdout);
#endif
  ios_base::sync_with_stdio(0);
  cin.tie(0);
  cout.tie(0);
}

struct custom_hash {
  static uint64_t splitmix64(uint64_t x) {
    x += 0x9e3779b97f4a7c15;
    x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
    x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
    return x ^ (x >> 31);
  }

  size_t operator()(uint64_t x) const {
    static const uint64_t FIXED_RANDOM =
        chrono::steady_clock::now().time_since_epoch().count();
    return splitmix64(x + FIXED_RANDOM);
  }
};

const int N = 1e5 + 1;
const double pi = acos(-1);

/*/-----------------------Modular Arithmetic---------------/*/
inline int add(int x, int y) {
  x += y;
  if (x >= mod)
    return x - mod;
  return x;
}
inline int sub(int x, int y) {
  x -= y;
  if (x < 0)
    return x + mod;
  return x;
}
inline int mul(int x, int y) { return (x * 1ll * y) % mod; }
/*/-----------------------------Code begins----------------------------------/*/

int parent[100005];
int R[100005];

int find(int a) {
  if (parent[a] == a)
    return a;
  return parent[a] = find(parent[a]);
}

void merge(int a, int b) {
  a = find(a);
  b = find(b);

  if (a == b)
    return;

  if (R[a] > R[b]) {
    parent[b] = a;
    R[a] += R[b];
  } else {
    parent[a] = b;
    R[b] += R[a];
  }
}

void init_par(int n) {
  fo(i, n) {
    R[i] = 1;
    parent[i] = i;
  }
}

void solve() {

  int n, q;
  cin >> n >> q;
  init_par(n);
  while (q--) {
    int type;
    cin >> type;
    if (type == 0) {
      int a, b;
      cin >> a >> b;
      merge(a, b);
    } else {
      int a, b;
      cin >> a >> b;
      if (find(a) == find(b))
        cout << "1\\n";
      else
        cout << "0\\n";
    }
  }
}

int32_t main() {
  babuBhaiya();

  int t;

  t = 1;
  // cin>>t;

  while (t--) {
    solve();
  }

  return 0;
}

// #pragma GCC optimize("Ofast")
// #pragma GCC target("avx,avx2,fma")
// #pragma GCC optimization ("unroll-loops")

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
using namespace __gnu_pbds;
using namespace std;

#define fo(i, n) for (int i = 0; i < n; i++)
#define nl "\\n"
#define ff first
#define ss second
#define int long long
#define pb push_back
#define mp make_pair
#define vec(x) vector<x>
#define matrix(x) vector<vector<x>>
#define sz(x) (int)x.size()
#define mem(a, b) memset(a, b, sizeof a)
#define vii vector<pair<int, int>>
#define pii pair<int, int>
#define vi vector<int>
#define mii map<int, int>
#define uii unordered_map<int, int, custom_hash>
#define pqb priority_queue<int>
#define pqs priority_queue<int, vi, greater<int>>
#define gcd(a, b) __gcd(a, b)
#define lcm(a, b) (a * (b / gcd(a, b)))
#define setbits(x) __builtin_popcountll(x)
#define zrobits(x) __builtin_ctzll(x)
#define mod 1000000007
#define MOD 998244353
#define inf 1e18
#define ps(x, y) fixed << setprecision(y) << x
#define mk(arr, n, type) type *arr = new type[n];
#define w(x)                                                                   \\
  int x;                                                                       \\
  cin >> x;                                                                    \\
  while (x--)
#define all(v) v.begin(), v.end()
#define rep(i, begin, end)                                                     \\
  for (__typeof(end) i = (begin) - ((begin) > (end));                          \\
       i != (end) - ((begin) > (end)); i += 1 - 2 * ((begin) > (end)))
#define len(s) s.length()

#define watch(x) cout << #x << " = " << x << endl

#define deb(...) cerr << "[" << #__VA_ARGS__ << "] : [", DBG(__VA_ARGS__)
void DBG() { cerr << "]\\n"; }
template <typename T, typename... Args> void DBG(T first, Args... args) {
  cerr << first;
  if (sizeof...(args))
    cerr << ", ";
  DBG(args...);
}

mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());

typedef tree<int, null_type, less<int>, rb_tree_tag,
             tree_order_statistics_node_update>
    pbds; // for storing unique elements
typedef tree<int, null_type, less_equal<int>, rb_tree_tag,
             tree_order_statistics_node_update>
    ordered_set; // for repeating elements

int power(int a, int b, int m = mod) {
  int ans = 1;
  while (b > 0) {
    if (b & 1)
      ans = (ans * a) % m;
    a = (a * a) % m;
    b >>= 1;
  }
  return ans;
}

void babuBhaiya() {
#ifndef ONLINE_JUDGE
  freopen("input.txt", "r", stdin);
  freopen("output.txt", "w", stdout);
#endif
  ios_base::sync_with_stdio(0);
  cin.tie(0);
  cout.tie(0);
}

struct custom_hash {
  static uint64_t splitmix64(uint64_t x) {
    x += 0x9e3779b97f4a7c15;
    x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
    x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
    return x ^ (x >> 31);
  }

  size_t operator()(uint64_t x) const {
    static const uint64_t FIXED_RANDOM =
        chrono::steady_clock::now().time_since_epoch().count();
    return splitmix64(x + FIXED_RANDOM);
  }
};

const int N = 1e5 + 1;
const double pi = acos(-1);

/*/-----------------------Modular Arithmetic---------------/*/
inline int add(int x, int y) {
  x += y;
  if (x >= mod)
    return x - mod;
  return x;
}
inline int sub(int x, int y) {
  x -= y;
  if (x < 0)
    return x + mod;
  return x;
}
inline int mul(int x, int y) { return (x * 1ll * y) % mod; }
/*/-----------------------------Code begins----------------------------------/*/

int parent[200005];
int R[200005];

int find(int a) {
  if (parent[a] == a)
    return a;
  return parent[a] = find(parent[a]);
}

void merge(int a, int b) {
  a = find(a);
  b = find(b);

  if (a == b)
    return;

  if (R[a] > R[b]) {
    parent[b] = a;
    R[a] += R[b];
  } else {
    parent[a] = b;
    R[b] += R[a];
  }
}

void init_par(int n) {
  fo(i, n) {
    R[i] = 1;
    parent[i] = i;
  }
}

void solve() {

  int n, q;
  cin >> n >> q;
  init_par(n);
  while (q--) {
    int type;
    cin >> type;
    if (type == 0) {
      int a, b;
      cin >> a >> b;
      merge(a, b);
    } else {
      int a, b;
      cin >> a >> b;
      if (find(a) == find(b))
        cout << "1\\n";
      else
        cout << "0\\n";
    }
  }
}

int32_t main() {
  babuBhaiya();

  int t;

  t = 1;
  // cin>>t;

  while (t--) {
    solve();
  }

  return 0;
}


#include <bits/stdc++.h>
using namespace std;
#define fastio                                                                 \\
  ios_base::sync_with_stdio(0);                                                \\
  cin.tie(0);                                                                  \\
  cout.tie(0)
const int Mxn = 200005;
int p[Mxn];

int par(int u) {
  if (p[u] == u)
    return u;

  return (p[u] = par(p[u]));
}

int uni(int a, int b) {
  int p1 = par(a);
  int p2 = par(b);
  p[p2] = p1;
}

int main() {
  fastio;
  int n, q;
  cin >> n >> q;

  for (int i = 1; i <= n; i++)
    p[i] = i;
  while (q--) {
    int t, u, v;
    cin >> t >> u >> v;
    if (t == 0) {
      uni(u, v);
    } else {
      cout << (par(u) == par(v) ? 1 : 0) << "\\n";
    }
  }
  return 0;
}

#include <bits/stdc++.h>
using namespace std;
#define fastio                                                                 \\
  ios_base::sync_with_stdio(0);                                                \\
  cin.tie(0);                                                                  \\
  cout.tie(0)
const int Mxn = 200005;
int p[Mxn];

int par(int u) {
  if (p[u] == u)
    return u;

  return (p[u] = par(p[u]));
}

void uni(int a, int b) {
  int p1 = par(a);
  int p2 = par(b);
  p[p2] = p1;
}

int main() {
  fastio;
  int n, q;
  cin >> n >> q;

  for (int i = 1; i <= n; i++)
    p[i] = i;
  while (q--) {
    int t, u, v;
    cin >> t >> u >> v;
    if (t == 0) {
      uni(u, v);
    } else {
      cout << (par(u) == par(v) ? 1 : 0) << "\\n";
    }
  }
  return 0;
}


// #Sazaの1日1AC
#include <bits/stdc++.h>
using namespace std;
const long long mod = 1000000000 + 7;
const long long INF = 9e18;
const double PI = 3.14159265358979323846;

// マクロ
// 型エイリアス
using ll = long long;
using P = pair<long long, long long>;
using vl = vector<long long>;
using vvl = vector<vector<long long>>;
using vP = vector<pair<long long, long long>>;
// ショートカット
#define rep(i, n) for (long long i = 0; i < n; i++)
#define rep2(i, k, n) for (long long i = k; i < n; i++) // 半開区間
#define all(v) v.begin(), v.end()
#define rall(v) v.rbegin(), v.rend()
#define pb push_back
#define mkp make_pair
// 入力
#define vin(v, N)                                                              \\
  for (long long i = 0; i < N; i++)                                            \\
  cin >> v.at(i)
#define lin(n)                                                                 \\
  long long n;                                                                 \\
  cin >> n
#define chin(x)                                                                \\
  char x;                                                                      \\
  cin >> x;
#define sin(s)                                                                 \\
  string s;                                                                    \\
  cin >> s;
#define vlin(v, N)                                                             \\
  vector<long long> v(N);                                                      \\
  for (long long i = 0; i < N; i++)                                            \\
  cin >> v.at(i)

#define max(a, b) max((ll)a, (ll)b)
#define min(a, b) min((ll)a, (ll)b)

// 関数
// 最大公約数
long long gcd(long long m, long long n) {
  long long a = max(m, n);
  long long b = min(m, n);
  long long r = a % b;
  while (r != 0) {
    a = b;
    b = r;
    r = a % b;
  }
  return b;
}
// 最小公倍数
long long lcd(long long m, long long n) { return m * n / gcd(m, n); }
// xのn乗
long long power(long long x, long long N) {
  long long ret = 1;
  for (long long i = 0; i < N; i++)
    ret *= x;
  return ret;
}
// 繰り返し二乗法
long long repeat_squaring(long long x, long long n) {
  if (n == 0)
    return 1;
  else if (n % 2 == 0) {
    long long t = repeat_squaring(x, n / 2);
    return t * t % mod;
  } else
    return x * repeat_squaring(x, n - 1) % mod;
}
// 素因数分解(mapで返す)
map<long long, long long> factor(long long p) {
  ll p1 = p;
  map<long long, long long> ret;
  for (long long i = 2; i * i <= p1; i++) {
    while (p % i == 0) {
      ret[i]++;
      p /= i;
    }
  }
  if (p != 1)
    ret[p]++;
  return ret;
}
// 素数判定
bool is_prime(long long N) {
  for (long long i = 2; i * i <= N; i++) {
    if (N % i == 0)
      return false;
  }
  return true;
}
// 最大値更新
void chmax(long long &a, long long b) { a = max(a, b); }
// 最小値更新
void chmin(long long &a, long long b) { a = min(a, b); }

// 構造体

// Union-Find木
struct UnionFind {
  // メンバ変数
  vector<long long> par; // par[i]:=頂点iの親
  vector<long long> s; // s[i]:=頂点iが属する集合の個数(iが根のとき)

  // コンストラクタ
  UnionFind(long long N) : par(N), s(N) {
    for (long long i = 0; i < N; i++) {
      par[i] = i; // 最初はすべてが根として初期化
      s[i] = 1;
    }
  }
  // メンバ関数
  // root(i):=頂点iの根
  long long root(long long i) {
    if (par[i] == i)
      return i;
    par[i] = root(par[i]); // 経路圧縮
    return root(par[i]);   // 再帰
  }
  // size[i]:=iが属する集合の個数
  long long size(long long i) { return s[root(i)]; }
  // same(x,y) xとyが同じ根を持つか(同じ集合に含まれるか)
  bool same(long long x, long long y) { return root(x) == root(y); }
  // unite(x,y) xの根をyの根に繋げる(集合を合併)
  void unite(long long x, long long y) {
    if (!same(x, y)) {
      long long rx = root(x);
      long long ry = root(y);
      par[rx] = par[ry];
      s[ry] = s[rx] + s[ry];
    }
  }
};

/////////////////⊂('ω'⊂ )))Σ≡GO!/////////////////

// メイン関数
int main() {
  // doubleの桁数

  lin(N);
  lin(Q);
  UnionFind T(N);
  rep(i, Q) {
    lin(t);
    lin(u);
    lin(v);
    u--;
    v--;
    if (t == 0)
      T.unite(u, v);
    else {
      if (T.same(u, v))
        cout << 1 << endl;
      else
        cout << 0 << endl;
    }
  }
}

// #Sazaの1日1AC
#include <bits/stdc++.h>
using namespace std;
const long long mod = 1000000000 + 7;
const long long INF = 9e18;
const double PI = 3.14159265358979323846;

// マクロ
// 型エイリアス
using ll = long long;
using P = pair<long long, long long>;
using vl = vector<long long>;
using vvl = vector<vector<long long>>;
using vP = vector<pair<long long, long long>>;
// ショートカット
#define rep(i, n) for (long long i = 0; i < n; i++)
#define rep2(i, k, n) for (long long i = k; i < n; i++) // 半開区間
#define all(v) v.begin(), v.end()
#define rall(v) v.rbegin(), v.rend()
#define pb push_back
#define mkp make_pair
// 入力
#define vin(v, N)                                                              \\
  for (long long i = 0; i < N; i++)                                            \\
  cin >> v.at(i)
#define lin(n)                                                                 \\
  long long n;                                                                 \\
  cin >> n
#define chin(x)                                                                \\
  char x;                                                                      \\
  cin >> x;
#define sin(s)                                                                 \\
  string s;                                                                    \\
  cin >> s;
#define vlin(v, N)                                                             \\
  vector<long long> v(N);                                                      \\
  for (long long i = 0; i < N; i++)                                            \\
  cin >> v.at(i)

#define max(a, b) max((ll)a, (ll)b)
#define min(a, b) min((ll)a, (ll)b)

// 関数
// 最大公約数
long long gcd(long long m, long long n) {
  long long a = max(m, n);
  long long b = min(m, n);
  long long r = a % b;
  while (r != 0) {
    a = b;
    b = r;
    r = a % b;
  }
  return b;
}
// 最小公倍数
long long lcd(long long m, long long n) { return m * n / gcd(m, n); }
// xのn乗
long long power(long long x, long long N) {
  long long ret = 1;
  for (long long i = 0; i < N; i++)
    ret *= x;
  return ret;
}
// 繰り返し二乗法
long long repeat_squaring(long long x, long long n) {
  if (n == 0)
    return 1;
  else if (n % 2 == 0) {
    long long t = repeat_squaring(x, n / 2);
    return t * t % mod;
  } else
    return x * repeat_squaring(x, n - 1) % mod;
}
// 素因数分解(mapで返す)
map<long long, long long> factor(long long p) {
  ll p1 = p;
  map<long long, long long> ret;
  for (long long i = 2; i * i <= p1; i++) {
    while (p % i == 0) {
      ret[i]++;
      p /= i;
    }
  }
  if (p != 1)
    ret[p]++;
  return ret;
}
// 素数判定
bool is_prime(long long N) {
  for (long long i = 2; i * i <= N; i++) {
    if (N % i == 0)
      return false;
  }
  return true;
}
// 最大値更新
void chmax(long long &a, long long b) { a = max(a, b); }
// 最小値更新
void chmin(long long &a, long long b) { a = min(a, b); }

// 構造体

// Union-Find木
struct UnionFind {
  // メンバ変数
  vector<long long> par; // par[i]:=頂点iの親
  vector<long long> s; // s[i]:=頂点iが属する集合の個数(iが根のとき)

  // コンストラクタ
  UnionFind(long long N) : par(N), s(N) {
    for (long long i = 0; i < N; i++) {
      par[i] = i; // 最初はすべてが根として初期化
      s[i] = 1;
    }
  }
  // メンバ関数
  // root(i):=頂点iの根
  long long root(long long i) {
    if (par[i] == i)
      return i;
    par[i] = root(par[i]); // 経路圧縮
    return root(par[i]);   // 再帰
  }
  // size[i]:=iが属する集合の個数
  long long size(long long i) { return s[root(i)]; }
  // same(x,y) xとyが同じ根を持つか(同じ集合に含まれるか)
  bool same(long long x, long long y) { return root(x) == root(y); }
  // unite(x,y) xの根をyの根に繋げる(集合を合併)
  void unite(long long x, long long y) {
    if (!same(x, y)) {
      long long rx = root(x);
      long long ry = root(y);
      par[rx] = par[ry];
      s[ry] = s[rx] + s[ry];
    }
  }
};

/////////////////⊂('ω'⊂ )))Σ≡GO!/////////////////

// メイン関数
int main() {
  // doubleの桁数

  lin(N);
  lin(Q);
  UnionFind T(N);
  rep(i, Q) {
    lin(t);
    lin(u);
    lin(v);
    if (t == 0)
      T.unite(u, v);
    else {
      if (T.same(u, v))
        cout << 1 << endl;
      else
        cout << 0 << endl;
    }
  }
}


#pragma GCC optimize("Ofast")
#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")
#pragma GCC target("avx")
#include <bits/stdc++.h>
#define _GLIBCXX_DEBUG
using namespace std;
using ll = long long;
using vec = vector<ll>;
using vect = vector<double>;
using Graph = vector<vector<ll>>;
#define endl '\\n'
#define loop(i, n) for (int i = 0; i < n; i++)
#define Loop(i, m, n) for (ll i = m; i < n; i++)
#define pool(i, n) for (ll i = n; i >= 0; i--)
#define Pool(i, m, n) for (ll i = n; i >= m; i--)
#define modd 1000000007ll
// #define modd 998244353ll
#define flagcount(bit) __builtin_popcount(bit)
#define flag(x) (1ll << x)
#define flagadd(bit, x) bit |= flag(x)
#define flagpop(bit, x) bit &= ~flag(x)
#define flagon(bit, i) bit &flag(i)
#define flagoff(bit, i) !(bit & (1ll << i))
#define all(v) v.begin(), v.end()
#define low2way(v, x) lower_bound(all(v), x)
#define high2way(v, x) upper_bound(all(v), x)
#define idx_lower(v, x)                                                        \\
  (distance(v.begin(), low2way(v, x))) // 配列vでx未満の要素数を返す
#define idx_upper(v, x)                                                        \\
  (distance(v.begin(), high2way(v, x))) // 配列vでx以下の要素数を返す
#define idx_lower2(v, x)                                                       \\
  (v.size() - idx_lower(v, x)) // 配列vでx以上の要素数を返す
#define idx_upper2(v, x)                                                       \\
  (v.size() - idx_upper(v, x)) // 配列vでxより大きい要素の数を返す
#define putout(a) cout << a << '\\n'
#define Sum(v) accumulate(all(v), 0ll)
ll ctoi(char c) {
  if (c >= '0' && c <= '9') {
    return c - '0';
  }
  return -1;
}
template <typename T> string make_string(T N) {
  string ret;
  T now = N;
  while (now > 0) {
    T x = now % 10;
    ret += (char)('0' + x);
    now /= 10;
  }
  reverse(all(ret));
  return ret;
}
template <typename T> T gcd(T a, T b) {
  if (a % b == 0) {
    return (b);
  } else {
    return (gcd(b, a % b));
  }
}
template <typename T> T lcm(T x, T y) {
  T z = gcd(x, y);
  return x * y / z;
}
template <typename T> bool primejudge(T n) {
  if (n < 2)
    return false;
  else if (n == 2)
    return true;
  else if (n % 2 == 0)
    return false;
  double sqrtn = sqrt(n);
  for (T i = 3; i < sqrtn + 1; i++) {
    if (n % i == 0) {
      return false;
    }
    i++;
  }
  return true;
}
template <typename T> bool chmax(T &a, const T &b) {
  if (a < b) {
    a = b; // aをbで更新
    return true;
  }
  return false;
}
template <typename T> bool chmin(T &a, const T &b) {
  if (a > b) {
    a = b; // aをbで更新
    return true;
  }
  return false;
}
// 場合によって使い分ける
// const ll dx[4]={1,0,-1,0};
// const ll dy[4]={0,1,0,-1};
const ll dx[8] = {1, 1, 0, -1, -1, -1, 0, 1};
const ll dy[8] = {0, 1, 1, 1, 0, -1, -1, -1};
class FastIO {
  static const int rdata_sz = (1 << 19), wdata_sz = (1 << 19);
  char rdata[rdata_sz], wdata[wdata_sz], *rb, *wb;
  char tmp_s[20];

public:
  FastIO() {
    fread(rdata, 1, rdata_sz, stdin);
    rb = rdata;
    wb = wdata;
  }
  ~FastIO() { fwrite(wdata, 1, wb - wdata, stdout); }

  template <typename T> inline void read(T &x) {
    bool neg = false;
    x = 0;
    while ((*rb < '0' || *rb > '9') && *rb != '-')
      ++rb;
    if (*rb == '-') {
      neg = true;
      ++rb;
    }
    while ('0' <= *rb && *rb <= '9') {
      x = 10 * x + (*rb - '0');
      ++rb;
    }
    if (neg)
      x = -x;
  }

#define pc(x) *(wb++) = x
  template <typename T> inline void write(T x) {
    if (x == 0) {
      pc('0');
      pc('\\n');
      return;
    }
    if (x < 0) {
      pc('-');
      x = -x;
    }
    char *t = tmp_s;
    while (x) {
      T y = x / 10;
      *(t++) = (x - y * 10) + '0';
      x = y;
    }
    while (t != tmp_s)
      pc(*(--t));
    pc('\\n');
  }
#undef pc
};
struct union_find {
  vector<int> par;  // 親の番号
  vector<int> rank; // 木の深さ(根のランクは0)
  vector<int> siz;  // 要素xが根なら木の頂点数を格納する
  // 初期化子リストを用いた初期化
  union_find(int N) : par(N), rank(N), siz(N) {
    for (int i = 0; i < N; i++) {
      par[i] = i;
      rank[i] = 0;
      siz[i] = 1;
    }
  }
  // 要素xが所属する木の根を再帰的に発見する
  int root(int x) {
    if (par[x] == x)
      return x;
    return par[x] = root(par[x]); // 経路圧縮
  }
  // 要素xが属する木と要素yが属する木の併合
  void unite(int x, int y) {
    int rx = root(x);
    int ry = root(y);
    if (rx == ry)
      return; // 同じ木に属してたらそのまま
    if (rank[rx] < rank[ry]) {
      par[rx] = ry; // 根がryの木に併合
      siz[ry] = siz[rx] + siz[ry];
    } else {
      par[ry] = rx; // 根がrxの木に併合
      siz[rx] = siz[rx] + siz[ry];
      if (rank[rx] == rank[ry])
        rank[rx]++;
    }
  }
  // 要素xが属する木と要素yが属する木が同じならtrueを返す
  bool same(int x, int y) { return root(x) == root(y); }
  // 要素xが属する木の頂点数を返す
  int size(int x) { return siz[root(x)]; }
};
int main() {
  FastIO io;
  int N, Q;
  io.read(N);
  io.read(Q);
  union_find tree(N);
  for (int i = 0; i < Q; i++) {
    int t, u, v;
    io.read(t);
    io.read(u);
    io.read(v);
    if (t)
      if (tree.same(u, v))
        io.write(1);
      else
        io.write(0);
    if (!t)
      tree.unite(u, v);
  }
  return 0;
}

#pragma GCC optimize("Ofast")
#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")
#pragma GCC target("avx")
#include <bits/stdc++.h>
#define _GLIBCXX_DEBUG
using namespace std;
using ll = long long;
using vec = vector<ll>;
using vect = vector<double>;
using Graph = vector<vector<ll>>;
#define endl '\\n'
#define loop(i, n) for (int i = 0; i < n; i++)
#define Loop(i, m, n) for (ll i = m; i < n; i++)
#define pool(i, n) for (ll i = n; i >= 0; i--)
#define Pool(i, m, n) for (ll i = n; i >= m; i--)
#define modd 1000000007ll
// #define modd 998244353ll
#define flagcount(bit) __builtin_popcount(bit)
#define flag(x) (1ll << x)
#define flagadd(bit, x) bit |= flag(x)
#define flagpop(bit, x) bit &= ~flag(x)
#define flagon(bit, i) bit &flag(i)
#define flagoff(bit, i) !(bit & (1ll << i))
#define all(v) v.begin(), v.end()
#define low2way(v, x) lower_bound(all(v), x)
#define high2way(v, x) upper_bound(all(v), x)
#define idx_lower(v, x)                                                        \\
  (distance(v.begin(), low2way(v, x))) // 配列vでx未満の要素数を返す
#define idx_upper(v, x)                                                        \\
  (distance(v.begin(), high2way(v, x))) // 配列vでx以下の要素数を返す
#define idx_lower2(v, x)                                                       \\
  (v.size() - idx_lower(v, x)) // 配列vでx以上の要素数を返す
#define idx_upper2(v, x)                                                       \\
  (v.size() - idx_upper(v, x)) // 配列vでxより大きい要素の数を返す
#define putout(a) cout << a << '\\n'
#define Sum(v) accumulate(all(v), 0ll)
ll ctoi(char c) {
  if (c >= '0' && c <= '9') {
    return c - '0';
  }
  return -1;
}
template <typename T> string make_string(T N) {
  string ret;
  T now = N;
  while (now > 0) {
    T x = now % 10;
    ret += (char)('0' + x);
    now /= 10;
  }
  reverse(all(ret));
  return ret;
}
template <typename T> T gcd(T a, T b) {
  if (a % b == 0) {
    return (b);
  } else {
    return (gcd(b, a % b));
  }
}
template <typename T> T lcm(T x, T y) {
  T z = gcd(x, y);
  return x * y / z;
}
template <typename T> bool primejudge(T n) {
  if (n < 2)
    return false;
  else if (n == 2)
    return true;
  else if (n % 2 == 0)
    return false;
  double sqrtn = sqrt(n);
  for (T i = 3; i < sqrtn + 1; i++) {
    if (n % i == 0) {
      return false;
    }
    i++;
  }
  return true;
}
template <typename T> bool chmax(T &a, const T &b) {
  if (a < b) {
    a = b; // aをbで更新
    return true;
  }
  return false;
}
template <typename T> bool chmin(T &a, const T &b) {
  if (a > b) {
    a = b; // aをbで更新
    return true;
  }
  return false;
}
// 場合によって使い分ける
// const ll dx[4]={1,0,-1,0};
// const ll dy[4]={0,1,0,-1};
const ll dx[8] = {1, 1, 0, -1, -1, -1, 0, 1};
const ll dy[8] = {0, 1, 1, 1, 0, -1, -1, -1};
class FastIO {
  static const int rdata_sz = (1 << 25), wdata_sz = (1 << 25);
  char rdata[rdata_sz], wdata[wdata_sz], *rb, *wb;
  char tmp_s[20];

public:
  FastIO() {
    fread(rdata, 1, rdata_sz, stdin);
    rb = rdata;
    wb = wdata;
  }
  ~FastIO() { fwrite(wdata, 1, wb - wdata, stdout); }

  template <typename T> inline void read(T &x) {
    bool neg = false;
    x = 0;
    while ((*rb < '0' || *rb > '9') && *rb != '-')
      ++rb;
    if (*rb == '-') {
      neg = true;
      ++rb;
    }
    while ('0' <= *rb && *rb <= '9') {
      x = 10 * x + (*rb - '0');
      ++rb;
    }
    if (neg)
      x = -x;
  }

#define pc(x) *(wb++) = x
  template <typename T> inline void write(T x) {
    if (x == 0) {
      pc('0');
      pc('\\n');
      return;
    }
    if (x < 0) {
      pc('-');
      x = -x;
    }
    char *t = tmp_s;
    while (x) {
      T y = x / 10;
      *(t++) = (x - y * 10) + '0';
      x = y;
    }
    while (t != tmp_s)
      pc(*(--t));
    pc('\\n');
  }
#undef pc
};
struct union_find {
  vector<int> par;  // 親の番号
  vector<int> rank; // 木の深さ(根のランクは0)
  vector<int> siz;  // 要素xが根なら木の頂点数を格納する
  // 初期化子リストを用いた初期化
  union_find(int N) : par(N), rank(N), siz(N) {
    for (int i = 0; i < N; i++) {
      par[i] = i;
      rank[i] = 0;
      siz[i] = 1;
    }
  }
  // 要素xが所属する木の根を再帰的に発見する
  int root(int x) {
    if (par[x] == x)
      return x;
    return par[x] = root(par[x]); // 経路圧縮
  }
  // 要素xが属する木と要素yが属する木の併合
  void unite(int x, int y) {
    int rx = root(x);
    int ry = root(y);
    if (rx == ry)
      return; // 同じ木に属してたらそのまま
    if (rank[rx] < rank[ry]) {
      par[rx] = ry; // 根がryの木に併合
      siz[ry] = siz[rx] + siz[ry];
    } else {
      par[ry] = rx; // 根がrxの木に併合
      siz[rx] = siz[rx] + siz[ry];
      if (rank[rx] == rank[ry])
        rank[rx]++;
    }
  }
  // 要素xが属する木と要素yが属する木が同じならtrueを返す
  bool same(int x, int y) { return root(x) == root(y); }
  // 要素xが属する木の頂点数を返す
  int size(int x) { return siz[root(x)]; }
};
int main() {
  FastIO io;
  int N, Q;
  io.read(N);
  io.read(Q);
  union_find tree(N);
  for (int i = 0; i < Q; i++) {
    int t, u, v;
    io.read(t);
    io.read(u);
    io.read(v);
    if (t)
      if (tree.same(u, v))
        io.write(1);
      else
        io.write(0);
    if (!t)
      tree.unite(u, v);
  }
  return 0;
}


#pragma GCC optimize("Ofast")
#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")
#pragma GCC target("avx")
#include <bits/stdc++.h>
#define _GLIBCXX_DEBUG
using namespace std;
using ll = long long;
using vec = vector<ll>;
using vect = vector<double>;
using Graph = vector<vector<ll>>;
#define endl '\\n'
#define loop(i, n) for (int i = 0; i < n; i++)
#define Loop(i, m, n) for (ll i = m; i < n; i++)
#define pool(i, n) for (ll i = n; i >= 0; i--)
#define Pool(i, m, n) for (ll i = n; i >= m; i--)
#define modd 1000000007ll
// #define modd 998244353ll
#define flagcount(bit) __builtin_popcount(bit)
#define flag(x) (1ll << x)
#define flagadd(bit, x) bit |= flag(x)
#define flagpop(bit, x) bit &= ~flag(x)
#define flagon(bit, i) bit &flag(i)
#define flagoff(bit, i) !(bit & (1ll << i))
#define all(v) v.begin(), v.end()
#define low2way(v, x) lower_bound(all(v), x)
#define high2way(v, x) upper_bound(all(v), x)
#define idx_lower(v, x)                                                        \\
  (distance(v.begin(), low2way(v, x))) // 配列vでx未満の要素数を返す
#define idx_upper(v, x)                                                        \\
  (distance(v.begin(), high2way(v, x))) // 配列vでx以下の要素数を返す
#define idx_lower2(v, x)                                                       \\
  (v.size() - idx_lower(v, x)) // 配列vでx以上の要素数を返す
#define idx_upper2(v, x)                                                       \\
  (v.size() - idx_upper(v, x)) // 配列vでxより大きい要素の数を返す
#define putout(a) cout << a << '\\n'
#define Sum(v) accumulate(all(v), 0ll)
ll ctoi(char c) {
  if (c >= '0' && c <= '9') {
    return c - '0';
  }
  return -1;
}
template <typename T> string make_string(T N) {
  string ret;
  T now = N;
  while (now > 0) {
    T x = now % 10;
    ret += (char)('0' + x);
    now /= 10;
  }
  reverse(all(ret));
  return ret;
}
template <typename T> T gcd(T a, T b) {
  if (a % b == 0) {
    return (b);
  } else {
    return (gcd(b, a % b));
  }
}
template <typename T> T lcm(T x, T y) {
  T z = gcd(x, y);
  return x * y / z;
}
template <typename T> bool primejudge(T n) {
  if (n < 2)
    return false;
  else if (n == 2)
    return true;
  else if (n % 2 == 0)
    return false;
  double sqrtn = sqrt(n);
  for (T i = 3; i < sqrtn + 1; i++) {
    if (n % i == 0) {
      return false;
    }
    i++;
  }
  return true;
}
template <typename T> bool chmax(T &a, const T &b) {
  if (a < b) {
    a = b; // aをbで更新
    return true;
  }
  return false;
}
template <typename T> bool chmin(T &a, const T &b) {
  if (a > b) {
    a = b; // aをbで更新
    return true;
  }
  return false;
}
// 場合によって使い分ける
// const ll dx[4]={1,0,-1,0};
// const ll dy[4]={0,1,0,-1};
const ll dx[8] = {1, 1, 0, -1, -1, -1, 0, 1};
const ll dy[8] = {0, 1, 1, 1, 0, -1, -1, -1};
class FastIO {
  static const int rdata_sz = (1 << 20), wdata_sz = (1 << 20);
  char rdata[rdata_sz], wdata[wdata_sz], *rb, *wb;
  char tmp_s[20];

public:
  FastIO() {
    fread(rdata, 1, rdata_sz, stdin);
    rb = rdata;
    wb = wdata;
  }
  ~FastIO() { fwrite(wdata, 1, wb - wdata, stdout); }

  template <typename T> inline void read(T &x) {
    bool neg = false;
    x = 0;
    while ((*rb < '0' || *rb > '9') && *rb != '-')
      ++rb;
    if (*rb == '-') {
      neg = true;
      ++rb;
    }
    while ('0' <= *rb && *rb <= '9') {
      x = 10 * x + (*rb - '0');
      ++rb;
    }
    if (neg)
      x = -x;
  }

#define pc(x) *(wb++) = x
  template <typename T> inline void write(T x) {
    if (x == 0) {
      pc('0');
      pc('\\n');
      return;
    }
    if (x < 0) {
      pc('-');
      x = -x;
    }
    char *t = tmp_s;
    while (x) {
      T y = x / 10;
      *(t++) = (x - y * 10) + '0';
      x = y;
    }
    while (t != tmp_s)
      pc(*(--t));
    pc('\\n');
  }
#undef pc
};
struct union_find {
  vector<int> par;  // 親の番号
  vector<int> rank; // 木の深さ(根のランクは0)
  vector<int> siz;  // 要素xが根なら木の頂点数を格納する
  // 初期化子リストを用いた初期化
  union_find(int N) : par(N), rank(N), siz(N) {
    for (int i = 0; i < N; i++) {
      par[i] = i;
      rank[i] = 0;
      siz[i] = 1;
    }
  }
  // 要素xが所属する木の根を再帰的に発見する
  int root(int x) {
    if (par[x] == x)
      return x;
    return par[x] = root(par[x]); // 経路圧縮
  }
  // 要素xが属する木と要素yが属する木の併合
  void unite(int x, int y) {
    int rx = root(x);
    int ry = root(y);
    if (rx == ry)
      return; // 同じ木に属してたらそのまま
    if (rank[rx] < rank[ry]) {
      par[rx] = ry; // 根がryの木に併合
      siz[ry] = siz[rx] + siz[ry];
    } else {
      par[ry] = rx; // 根がrxの木に併合
      siz[rx] = siz[rx] + siz[ry];
      if (rank[rx] == rank[ry])
        rank[rx]++;
    }
  }
  // 要素xが属する木と要素yが属する木が同じならtrueを返す
  bool same(int x, int y) { return root(x) == root(y); }
  // 要素xが属する木の頂点数を返す
  int size(int x) { return siz[root(x)]; }
};
int main() {
  FastIO io;
  int N, Q;
  io.read(N);
  io.read(Q);
  union_find tree(N);
  for (int i = 0; i < Q; i++) {
    int a, b, c;
    io.read(a);
    io.read(b);
    io.read(c);
    if (a == 1)
      if (tree.same(b, c))
        io.write(1);
      else
        io.write(0);
    if (a == 0)
      tree.unite(b, c);
  }
  return 0;
}

#pragma GCC optimize("Ofast")
#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")
#pragma GCC target("avx")
#include <bits/stdc++.h>
#define _GLIBCXX_DEBUG
using namespace std;
using ll = long long;
using vec = vector<ll>;
using vect = vector<double>;
using Graph = vector<vector<ll>>;
#define endl '\\n'
#define loop(i, n) for (int i = 0; i < n; i++)
#define Loop(i, m, n) for (ll i = m; i < n; i++)
#define pool(i, n) for (ll i = n; i >= 0; i--)
#define Pool(i, m, n) for (ll i = n; i >= m; i--)
#define modd 1000000007ll
// #define modd 998244353ll
#define flagcount(bit) __builtin_popcount(bit)
#define flag(x) (1ll << x)
#define flagadd(bit, x) bit |= flag(x)
#define flagpop(bit, x) bit &= ~flag(x)
#define flagon(bit, i) bit &flag(i)
#define flagoff(bit, i) !(bit & (1ll << i))
#define all(v) v.begin(), v.end()
#define low2way(v, x) lower_bound(all(v), x)
#define high2way(v, x) upper_bound(all(v), x)
#define idx_lower(v, x)                                                        \\
  (distance(v.begin(), low2way(v, x))) // 配列vでx未満の要素数を返す
#define idx_upper(v, x)                                                        \\
  (distance(v.begin(), high2way(v, x))) // 配列vでx以下の要素数を返す
#define idx_lower2(v, x)                                                       \\
  (v.size() - idx_lower(v, x)) // 配列vでx以上の要素数を返す
#define idx_upper2(v, x)                                                       \\
  (v.size() - idx_upper(v, x)) // 配列vでxより大きい要素の数を返す
#define putout(a) cout << a << '\\n'
#define Sum(v) accumulate(all(v), 0ll)
ll ctoi(char c) {
  if (c >= '0' && c <= '9') {
    return c - '0';
  }
  return -1;
}
template <typename T> string make_string(T N) {
  string ret;
  T now = N;
  while (now > 0) {
    T x = now % 10;
    ret += (char)('0' + x);
    now /= 10;
  }
  reverse(all(ret));
  return ret;
}
template <typename T> T gcd(T a, T b) {
  if (a % b == 0) {
    return (b);
  } else {
    return (gcd(b, a % b));
  }
}
template <typename T> T lcm(T x, T y) {
  T z = gcd(x, y);
  return x * y / z;
}
template <typename T> bool primejudge(T n) {
  if (n < 2)
    return false;
  else if (n == 2)
    return true;
  else if (n % 2 == 0)
    return false;
  double sqrtn = sqrt(n);
  for (T i = 3; i < sqrtn + 1; i++) {
    if (n % i == 0) {
      return false;
    }
    i++;
  }
  return true;
}
template <typename T> bool chmax(T &a, const T &b) {
  if (a < b) {
    a = b; // aをbで更新
    return true;
  }
  return false;
}
template <typename T> bool chmin(T &a, const T &b) {
  if (a > b) {
    a = b; // aをbで更新
    return true;
  }
  return false;
}
// 場合によって使い分ける
// const ll dx[4]={1,0,-1,0};
// const ll dy[4]={0,1,0,-1};
const ll dx[8] = {1, 1, 0, -1, -1, -1, 0, 1};
const ll dy[8] = {0, 1, 1, 1, 0, -1, -1, -1};
class FastIO {
  static const int rdata_sz = (1 << 23), wdata_sz = (1 << 23);
  char rdata[rdata_sz], wdata[wdata_sz], *rb, *wb;
  char tmp_s[20];

public:
  FastIO() {
    fread(rdata, 1, rdata_sz, stdin);
    rb = rdata;
    wb = wdata;
  }
  ~FastIO() { fwrite(wdata, 1, wb - wdata, stdout); }

  template <typename T> inline void read(T &x) {
    bool neg = false;
    x = 0;
    while ((*rb < '0' || *rb > '9') && *rb != '-')
      ++rb;
    if (*rb == '-') {
      neg = true;
      ++rb;
    }
    while ('0' <= *rb && *rb <= '9') {
      x = 10 * x + (*rb - '0');
      ++rb;
    }
    if (neg)
      x = -x;
  }

#define pc(x) *(wb++) = x
  template <typename T> inline void write(T x) {
    if (x == 0) {
      pc('0');
      pc('\\n');
      return;
    }
    if (x < 0) {
      pc('-');
      x = -x;
    }
    char *t = tmp_s;
    while (x) {
      T y = x / 10;
      *(t++) = (x - y * 10) + '0';
      x = y;
    }
    while (t != tmp_s)
      pc(*(--t));
    pc('\\n');
  }
#undef pc
};
struct union_find {
  vector<int> par;  // 親の番号
  vector<int> rank; // 木の深さ(根のランクは0)
  vector<int> siz;  // 要素xが根なら木の頂点数を格納する
  // 初期化子リストを用いた初期化
  union_find(int N) : par(N), rank(N), siz(N) {
    for (int i = 0; i < N; i++) {
      par[i] = i;
      rank[i] = 0;
      siz[i] = 1;
    }
  }
  // 要素xが所属する木の根を再帰的に発見する
  int root(int x) {
    if (par[x] == x)
      return x;
    return par[x] = root(par[x]); // 経路圧縮
  }
  // 要素xが属する木と要素yが属する木の併合
  void unite(int x, int y) {
    int rx = root(x);
    int ry = root(y);
    if (rx == ry)
      return; // 同じ木に属してたらそのまま
    if (rank[rx] < rank[ry]) {
      par[rx] = ry; // 根がryの木に併合
      siz[ry] = siz[rx] + siz[ry];
    } else {
      par[ry] = rx; // 根がrxの木に併合
      siz[rx] = siz[rx] + siz[ry];
      if (rank[rx] == rank[ry])
        rank[rx]++;
    }
  }
  // 要素xが属する木と要素yが属する木が同じならtrueを返す
  bool same(int x, int y) { return root(x) == root(y); }
  // 要素xが属する木の頂点数を返す
  int size(int x) { return siz[root(x)]; }
};
int main() {
  FastIO io;
  int N, Q;
  io.read(N);
  io.read(Q);
  union_find tree(N);
  for (int i = 0; i < Q; i++) {
    int a, b, c;
    io.read(a);
    io.read(b);
    io.read(c);
    if (a == 1)
      if (tree.same(b, c))
        io.write(1);
      else
        io.write(0);
    if (a == 0)
      tree.unite(b, c);
  }
  return 0;
}


#include <algorithm>
#include <cmath>
#include <deque>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <string>
#include <utility>
#include <vector>
#define MOD 1000000007
using namespace std;
typedef long long ll;
#include <cstring>

int n, m;

struct unionfind {
  int parent;
  int node;
  int edge;
};
unionfind g[100001];

void init() {
  for (int i = 0; i <= n; i++) {
    g[i].parent = i;
    g[i].node = 1;
    g[i].edge = 0;
  }
}

int find(int x) {
  if (x == g[x].parent) {
    return x;
  }
  int res = find(g[x].parent);
  g[x].node = g[res].node;
  g[x].edge = g[res].edge;
  g[x].parent = res;
  return res;
}

void merge(int x, int y) {
  if (x > y) {
    x ^= y;
    y ^= x;
    x ^= y;
  }
  g[x].node += g[y].node;
  g[x].edge += g[y].edge + 1;
  g[y].parent = x;
}

int main() {
  int q, a, u, v;
  cin >> n >> q;
  init();
  for (int i = 0; i < q; i++) {
    cin >> a >> u >> v;
    u = find(u);
    v = find(v);
    if (a == 0 && u != v) {
      merge(u, v);
    } else if (a == 1) {
      cout << (u == v ? 1 : 0) << endl;
    }
  }
}

#include <algorithm>
#include <cmath>
#include <deque>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <string>
#include <utility>
#include <vector>
#define MOD 1000000007
using namespace std;
typedef long long ll;
#include <cstring>

int n, m;

struct unionfind {
  int parent;
  int node;
  int edge;
};
unionfind g[200001];

void init() {
  for (int i = 0; i <= n; i++) {
    g[i].parent = i;
    g[i].node = 1;
    g[i].edge = 0;
  }
}

int find(int x) {
  if (x == g[x].parent) {
    return x;
  }
  int res = find(g[x].parent);
  g[x].node = g[res].node;
  g[x].edge = g[res].edge;
  g[x].parent = res;
  return res;
}

void merge(int x, int y) {
  if (x > y) {
    x ^= y;
    y ^= x;
    x ^= y;
  }
  g[x].node += g[y].node;
  g[x].edge += g[y].edge + 1;
  g[y].parent = x;
}

int main() {
  int q, a, u, v;
  cin >> n >> q;
  init();
  for (int i = 0; i < q; i++) {
    cin >> a >> u >> v;
    u = find(u);
    v = find(v);
    if (a == 0 && u != v) {
      merge(u, v);
    } else if (a == 1) {
      cout << (u == v ? 1 : 0) << endl;
    }
  }
}


#include <bits/stdc++.h>
using namespace std;
int id[200010];
int root(int i) { return !id[i] ? i : id[i] = root(id[i]); }
int main() {
  int n, q;
  cin >> n >> q;
  while (q--) {
    int t, u, v;
    cin >> t >> u >> v;
    if (t) {
      cout << (root(u) == root(v)) << "\\n";
    } else {
      id[root(v)] = root(u);
    }
  }
}

#include <bits/stdc++.h>
using namespace std;
int id[200010];
int root(int i) { return !id[i] ? i : id[i] = root(id[i]); }
int main() {
  int n, q;
  cin >> n >> q;
  while (q--) {
    int t, u, v;
    cin >> t >> u >> v;
    u++, v++;
    if (t) {
      cout << (root(u) == root(v)) << "\\n";
    } else {
      if (root(v) != root(u))
        id[root(v)] = root(u);
    }
  }
}


#include <bits/stdc++.h>
using namespace std;
struct UnionFind {
  vector<int> par, size;
  UnionFind(int x) {
    par.resize(x);
    size.resize(x, 1);
    for (int i = 0; i < x; i++) {
      par[i] = i;
    }
  }
  int find(int x) {
    if (par[x] == x)
      return x;
    return par[x] = find(par[x]);
  }
  bool same(int x, int y) { return find(x) == find(y); }
  int consize(int x) { return size[find(x)]; }
  void unite(int x, int y) {
    x = find(x);
    y = find(y);
    if (x == y)
      return;
    if (size[x] < size[y]) {
      par[x] = y;
      size[y] += size[x];
    } else {
      par[y] = x;
      size[x] += size[y];
    }
  }
};
int main() {
  int N, M;
  cin >> N >> M;
  UnionFind Onion(M);
  for (int i = 0; i < M; i++) {
    int a, b, c;
    cin >> a >> b >> c;
    if (a == 0)
      Onion.unite(b, c);
    else
      cout << (Onion.same(b, c) ? 1 : 0) << endl;
  }
}

#include <bits/stdc++.h>
using namespace std;
struct UnionFind {
  vector<int> par, size;
  UnionFind(int x) {
    par.resize(x);
    size.resize(x, 1);
    for (int i = 0; i < x; i++) {
      par[i] = i;
    }
  }
  int find(int x) {
    if (par[x] == x)
      return x;
    return par[x] = find(par[x]);
  }
  bool same(int x, int y) { return find(x) == find(y); }
  int consize(int x) { return size[find(x)]; }
  void unite(int x, int y) {
    x = find(x);
    y = find(y);
    if (x == y)
      return;
    if (size[x] < size[y]) {
      par[x] = y;
      size[y] += size[x];
    } else {
      par[y] = x;
      size[x] += size[y];
    }
  }
};
int main() {
  int N, M;
  cin >> N >> M;
  UnionFind Onion(N);
  for (int i = 0; i < M; i++) {
    int a, b, c;
    cin >> a >> b >> c;
    if (a == 0)
      Onion.unite(b, c);
    else
      cout << (Onion.same(b, c) ? 1 : 0) << endl;
  }
}


#pragma GCC optimize("Ofast")
#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")
// #pragma GCC target("avx")
#include <bits/stdc++.h>
using namespace std;
class FastIO {
  static const unsigned int rdata_sz = (1 << 21), wdata_sz = (1 << 21);
  char rdata[rdata_sz], wdata[wdata_sz], *rb, *wb;
  char tmp_s[10];

public:
  FastIO() {
    fread(rdata, 1, rdata_sz, stdin);
    rb = rdata;
    wb = wdata;
  }
  ~FastIO() { fwrite(wdata, 1, wb - wdata, stdout); }

  template <typename T> inline void read(T &x) {
    bool neg = false;
    x = 0;
    while ((*rb < '0' || *rb > '9') && *rb != '-')
      ++rb;
    while ('0' <= *rb && *rb <= '9') {
      x = 10 * x + (*rb - '0');
      ++rb;
    }
    if (neg)
      x = -x;
  }

#define pc(x) *(wb++) = x
  template <typename T> inline void write(T x) {
    if (x == 0) {
      pc('0');
      pc(' ');
      return;
    }
    char *t = tmp_s;
    while (x) {
      T y = x / 10;
      *(t++) = (x - y * 10) + '0';
      x = y;
    }
    while (t != tmp_s)
      pc(*(--t));
    pc(' ');
  }
#undef pc
};
int par[500001];
int ran[500001];
// 要素xが所属する木の根を再帰的に発見する
inline int root(int x) {
  if (par[x] == x)
    return x;
  return par[x] = root(par[x]); // 経路圧縮
}
// 要素xが属する木と要素yが属する木の併合
inline void unite(int x, int y) {
  int rx = root(x);
  int ry = root(y);
  if (rx == ry)
    return; // 同じ木に属してたらそのまま
  if (ran[rx] < ran[ry]) {
    par[rx] = ry; // 根がryの木に併合
  } else {
    par[ry] = rx; // 根がrxの木に併合
    if (ran[rx] == ran[ry])
      ran[rx]++;
  }
}
// 要素xが属する木と要素yが属する木が同じならtrueを返す
inline bool same(int x, int y) { return root(x) == root(y); }
int main() {
  FastIO io;
  int N, Q;
  io.read(N);
  io.read(Q);
  for (int i = 0; i < N; i++) {
    par[i] = i;
    ran[i] = 0;
  }
  for (int i = 0; i < Q; i++) {
    int a, b, c;
    io.read(a);
    io.read(b);
    io.read(c);
    if (a == 1)
      if (same(b, c))
        io.write(1);
      else
        io.write(0);
    if (a == 0)
      unite(b, c);
  }
  return 0;
}

#pragma GCC optimize("Ofast")
#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")
#pragma GCC target("avx")
#include <bits/stdc++.h>
using namespace std;
class FastIO {
  static const int rdata_sz = (1 << 22), wdata_sz = (1 << 22);
  char rdata[rdata_sz], wdata[wdata_sz], *rb, *wb;
  char tmp_s[10];

public:
  FastIO() {
    fread(rdata, 1, rdata_sz, stdin);
    rb = rdata;
    wb = wdata;
  }
  ~FastIO() { fwrite(wdata, 1, wb - wdata, stdout); }

  template <typename T> inline void read(T &x) {
    bool neg = false;
    x = 0;
    while ((*rb < '0' || *rb > '9') && *rb != '-')
      ++rb;
    while ('0' <= *rb && *rb <= '9') {
      x = 10 * x + (*rb - '0');
      ++rb;
    }
    if (neg)
      x = -x;
  }

#define pc(x) *(wb++) = x
  template <typename T> inline void write(T x) {
    if (x == 0) {
      pc('0');
      pc(' ');
      return;
    }
    char *t = tmp_s;
    while (x) {
      T y = x / 10;
      *(t++) = (x - y * 10) + '0';
      x = y;
    }
    while (t != tmp_s)
      pc(*(--t));
    pc(' ');
  }
#undef pc
};
unsigned int par[500001];
unsigned int ran[500001];
// 要素xが所属する木の根を再帰的に発見する
inline unsigned int root(unsigned int x) {
  if (par[x] == x)
    return x;
  return par[x] = root(par[x]); // 経路圧縮
}
// 要素xが属する木と要素yが属する木の併合
inline void unite(unsigned int x, unsigned int y) {
  unsigned int rx = root(x);
  unsigned int ry = root(y);
  if (rx == ry)
    return; // 同じ木に属してたらそのまま
  if (ran[rx] < ran[ry]) {
    par[rx] = ry; // 根がryの木に併合
  } else {
    par[ry] = rx; // 根がrxの木に併合
    if (ran[rx] == ran[ry])
      ran[rx]++;
  }
}
// 要素xが属する木と要素yが属する木が同じならtrueを返す
inline bool same(unsigned int x, unsigned int y) { return root(x) == root(y); }
int main() {
  FastIO io;
  unsigned int N, Q;
  io.read(N);
  io.read(Q);
  for (unsigned int i = 0; i < N; i++) {
    par[i] = i;
    ran[i] = 0;
  }
  for (unsigned int i = 0; i < Q; i++) {
    unsigned int a, b, c;
    io.read(a);
    io.read(b);
    io.read(c);
    if (a == 1)
      if (same(b, c))
        io.write(1);
      else
        io.write(0);
    if (a == 0)
      unite(b, c);
  }
  return 0;
}


#include <bits/stdc++.h>
// #include <ext/pb_ds/assoc_container.hpp>
// #pragma GCC optimize ("trapv")
using namespace std;

#define pii pair<int, int>
#define pll pair<long long, long long>
#define fi first
#define se second
#define mp make_pair
#define pb push_back

#define DEBUG 1
#define cerr                                                                   \\
  if (DEBUG)                                                                   \\
  cerr
#define test cerr << "hi\\n";

// mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());
// #define rand(l, r) uniform_int_distribution<long long>(l, r)(rng)
// using namespace __gnu_pbds;
// typedef tree<int, null_type, less<int>, rb_tree_tag,
// tree_order_statistics_node_update> OST;

#define INF 0x3f3f3f3f3f3f3f3f
#define MAXN 200005
// #define MOD 998244353LL
#define MOD 1000000007LL

int n, m;
vector<pair<pii, int>> games;
int p[MAXN], col[MAXN];
vector<int> v[MAXN];

void join(int x, int y, int st) {
  x = p[x], y = p[y];
  if (v[x].size() < v[y].size())
    swap(x, y);
  while (v[y].size()) {
    int q = v[y].back();
    v[x].pb(q);
    p[q] = x;
    v[y].pop_back();
  }
}

int work(int go) {
  for (int i = 0; i < n; i++) {
    p[i] = i;
    v[i].clear();
    v[i].pb(i);
    col[i] = 0;
  }

  for (int i = 0; i < m; i++) {
    int u, v, st;
    u = games[i].fi.fi;
    v = games[i].fi.se;
    st = games[i].se;

    if (u == go or v == go)
      continue;

    if (p[u] != p[v]) {
      join(u, v, st);
    } else {
      if ((col[u] + st) % 3 != col[v])
        return i;
    }
  }

  return -1;
}

int val[255];
int q;

void solve() {
  cin >> n >> q;
  iota(p + 1, p + 1 + n, 1);
  for (int i = 0; i <= n; i++)
    v[i].pb(i);
  while (q--) {
    int t, u, v;
    cin >> t >> u >> v;
    if (t == 0) {
      join(u, v, 0);
    }
    if (t == 1) {
      cout << (p[u] == p[v]) << '\\n';
    }
  }
}

int main() {
#ifdef LOCAL
  freopen("input.txt", "r", stdin);
  //    freopen("output.txt", "w", stdout);
  auto start_time = clock();
#endif
  ios_base::sync_with_stdio(0);
  cin.tie(0);

  int t = 1;
  //    cin >> t;
  for (int no = 1; no <= t; no++) {
    //        cout << "Case #" << no << ": ";
    solve();
  }

#ifdef LOCAL
  cerr << "TIME ELAPSED: " << double(clock() - start_time) / CLOCKS_PER_SEC
       << '\\n';
#endif
}

#include <bits/stdc++.h>
// #include <ext/pb_ds/assoc_container.hpp>
// #pragma GCC optimize ("trapv")
using namespace std;

#define pii pair<int, int>
#define pll pair<long long, long long>
#define fi first
#define se second
#define mp make_pair
#define pb push_back

#define DEBUG 1
#define cerr                                                                   \\
  if (DEBUG)                                                                   \\
  cerr
#define test cerr << "hi\\n";

// mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());
// #define rand(l, r) uniform_int_distribution<long long>(l, r)(rng)
// using namespace __gnu_pbds;
// typedef tree<int, null_type, less<int>, rb_tree_tag,
// tree_order_statistics_node_update> OST;

#define INF 0x3f3f3f3f3f3f3f3f
#define MAXN 200005
// #define MOD 998244353LL
#define MOD 1000000007LL

int n, m;
vector<pair<pii, int>> games;
int p[MAXN], col[MAXN];
vector<int> v[MAXN];

void join(int x, int y, int st) {
  x = p[x], y = p[y];
  if (x == y)
    return;
  if (v[x].size() < v[y].size())
    swap(x, y);

  // v[x] > v[y]

  int col_shift = col[x] + st + 3 - col[y];

  int src = p[y];
  for (int i = 0; i < v[src].size(); i++) {
    int q = v[src][i];
    p[q] = p[x];
    v[p[x]].pb(q);
    (col[q] += col_shift) %= 3;
  }
  v[src].clear();
}

int work(int go) {
  for (int i = 0; i < n; i++) {
    p[i] = i;
    v[i].clear();
    v[i].pb(i);
    col[i] = 0;
  }

  for (int i = 0; i < m; i++) {
    int u, v, st;
    u = games[i].fi.fi;
    v = games[i].fi.se;
    st = games[i].se;

    if (u == go or v == go)
      continue;

    if (p[u] != p[v]) {
      join(u, v, st);
    } else {
      if ((col[u] + st) % 3 != col[v])
        return i;
    }
  }

  return -1;
}

int val[255];
int q;

void solve() {
  cin >> n >> q;
  iota(p + 1, p + 1 + n, 1);
  for (int i = 0; i <= n; i++)
    v[i].pb(i);
  while (q--) {
    int t, u, v;
    cin >> t >> u >> v;
    if (t == 0) {
      join(u, v, 0);
    }
    if (t == 1) {
      cout << (p[u] == p[v]) << '\\n';
    }
  }
}

int main() {
#ifdef LOCAL
  freopen("input.txt", "r", stdin);
  //    freopen("output.txt", "w", stdout);
  auto start_time = clock();
#endif
  ios_base::sync_with_stdio(0);
  cin.tie(0);

  int t = 1;
  //    cin >> t;
  for (int no = 1; no <= t; no++) {
    //        cout << "Case #" << no << ": ";
    solve();
  }

#ifdef LOCAL
  cerr << "TIME ELAPSED: " << double(clock() - start_time) / CLOCKS_PER_SEC
       << '\\n';
#endif
}


#include <bits/stdc++.h>
// #include <ext/pb_ds/assoc_container.hpp>
// #pragma GCC optimize ("trapv")
using namespace std;

#define pii pair<int, int>
#define pll pair<long long, long long>
#define fi first
#define se second
#define mp make_pair
#define pb push_back

#define DEBUG 1
#define cerr                                                                   \\
  if (DEBUG)                                                                   \\
  cerr
#define test cerr << "hi\\n";

// mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());
// #define rand(l, r) uniform_int_distribution<long long>(l, r)(rng)
// using namespace __gnu_pbds;
// typedef tree<int, null_type, less<int>, rb_tree_tag,
// tree_order_statistics_node_update> OST;

#define INF 0x3f3f3f3f3f3f3f3f
#define MAXN 200005
// #define MOD 998244353LL
#define MOD 1000000007LL

int n, m;
vector<pair<pii, int>> games;
int p[MAXN], col[MAXN];
vector<int> v[MAXN];

void join(int x, int y, int st) {
  if (v[p[x]].size() < v[p[y]].size()) {
    swap(x, y);
    st *= -1;
  }

  // v[x] > v[y]

  int col_shift = col[x] + st + 3 - col[y];

  int src = p[y];
  for (int i = 0; i < v[src].size(); i++) {
    int q = v[src][i];
    p[q] = p[x];
    v[p[x]].pb(q);
    (col[q] += col_shift) %= 3;
  }
  v[src].clear();
}

int work(int go) {
  for (int i = 0; i < n; i++) {
    p[i] = i;
    v[i].clear();
    v[i].pb(i);
    col[i] = 0;
  }

  for (int i = 0; i < m; i++) {
    int u, v, st;
    u = games[i].fi.fi;
    v = games[i].fi.se;
    st = games[i].se;

    if (u == go or v == go)
      continue;

    if (p[u] != p[v]) {
      join(u, v, st);
    } else {
      if ((col[u] + st) % 3 != col[v])
        return i;
    }
  }

  return -1;
}

int val[255];
int q;

void solve() {
  cin >> n >> q;
  iota(p + 1, p + 1 + n, 1);
  for (int i = 1; i <= n; i++)
    v[i].pb(i);
  while (q--) {
    int t, u, v;
    cin >> t >> u >> v;
    if (t == 0) {
      join(u, v, 0);
    }
    if (t == 1) {
      cout << (p[u] == p[v]) << '\\n';
    }
  }
}

int main() {
#ifdef LOCAL
  freopen("input.txt", "r", stdin);
  //    freopen("output.txt", "w", stdout);
  auto start_time = clock();
#endif
  ios_base::sync_with_stdio(0);
  cin.tie(0);

  int t = 1;
  //    cin >> t;
  for (int no = 1; no <= t; no++) {
    //        cout << "Case #" << no << ": ";
    solve();
  }

#ifdef LOCAL
  cerr << "TIME ELAPSED: " << double(clock() - start_time) / CLOCKS_PER_SEC
       << '\\n';
#endif
}

#include <bits/stdc++.h>
// #include <ext/pb_ds/assoc_container.hpp>
// #pragma GCC optimize ("trapv")
using namespace std;

#define pii pair<int, int>
#define pll pair<long long, long long>
#define fi first
#define se second
#define mp make_pair
#define pb push_back

#define DEBUG 1
#define cerr                                                                   \\
  if (DEBUG)                                                                   \\
  cerr
#define test cerr << "hi\\n";

// mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());
// #define rand(l, r) uniform_int_distribution<long long>(l, r)(rng)
// using namespace __gnu_pbds;
// typedef tree<int, null_type, less<int>, rb_tree_tag,
// tree_order_statistics_node_update> OST;

#define INF 0x3f3f3f3f3f3f3f3f
#define MAXN 200005
// #define MOD 998244353LL
#define MOD 1000000007LL

int n, m;
vector<pair<pii, int>> games;
int p[MAXN], col[MAXN];
vector<int> v[MAXN];

void join(int x, int y, int st) {
  x = p[x], y = p[y];
  if (x == y)
    return;
  if (v[x].size() < v[y].size())
    swap(x, y);
  while (v[y].size()) {
    int q = v[y].back();
    v[x].pb(q);
    p[q] = x;
    v[y].pop_back();
  }
}

int work(int go) {
  for (int i = 0; i < n; i++) {
    p[i] = i;
    v[i].clear();
    v[i].pb(i);
    col[i] = 0;
  }

  for (int i = 0; i < m; i++) {
    int u, v, st;
    u = games[i].fi.fi;
    v = games[i].fi.se;
    st = games[i].se;

    if (u == go or v == go)
      continue;

    if (p[u] != p[v]) {
      join(u, v, st);
    } else {
      if ((col[u] + st) % 3 != col[v])
        return i;
    }
  }

  return -1;
}

int val[255];
int q;

void solve() {
  cin >> n >> q;
  iota(p + 1, p + 1 + n, 1);
  for (int i = 0; i <= n; i++)
    v[i].pb(i);
  while (q--) {
    int t, u, v;
    cin >> t >> u >> v;
    if (t == 0) {
      join(u, v, 0);
    }
    if (t == 1) {
      cout << (p[u] == p[v]) << '\\n';
    }
  }
}

int main() {
#ifdef LOCAL
  freopen("input.txt", "r", stdin);
  //    freopen("output.txt", "w", stdout);
  auto start_time = clock();
#endif
  ios_base::sync_with_stdio(0);
  cin.tie(0);

  int t = 1;
  //    cin >> t;
  for (int no = 1; no <= t; no++) {
    //        cout << "Case #" << no << ": ";
    solve();
  }

#ifdef LOCAL
  cerr << "TIME ELAPSED: " << double(clock() - start_time) / CLOCKS_PER_SEC
       << '\\n';
#endif
}