Problem:
Disjoint Set

Write a program which manipulates a disjoint set S = {S1, S2, . . . , Sk}.

First of all, the program should read an integer n, then make a disjoint set where each element consists of 0, 1, ... n−1 respectively.

Next, the program should read an integer q and manipulate the set for q queries. There are two kinds of queries for different operations:

unite(x, y): unites sets that contain x and y, say Sx and Sy, into a new set.

same(x, y): determine whether x and y are in the same set.

Input

n q
com1 x1 y1
com2 x2 y2
...
comq xq yq

In the first line, n and q are given. Then, q queries are given where com represents the type of queries. '0' denotes unite and '1' denotes same operation.

Output

For each same operation, print 1 if x and y are in the same set, otherwise 0, in a line.

Constraints

1 ≤ n ≤ 10000

1 ≤ q ≤ 100000

x ≠ y

Sample Input

5 12
0 1 4
0 2 3
1 1 2
1 3 4
1 1 4
1 3 2
0 1 3
1 2 4
1 3 0
0 0 4
1 0 2
1 3 0

Sample Output

0
0
1
1
1
0
1
1

Solution in C# (judge verdict: Accepted)

using System;
using System.Linq;

namespace DSL1_A{
    public class Program{
        public static void Main(string[] args){
            var sr = new StreamReader();
            //---------------------------------
            var N = sr.Next<int>();
            var Q = sr.Next<int>();
            var query = sr.Next<int>(Q, 3).Select(a => new {com = a[0], x = a[1], y = a[2]}).ToArray();

            var uf = new UnionFind(N);
            foreach(var q in query){
                if(q.com == 0){
                    uf.Unite(q.x, q.y);
                }
                if(q.com == 1){
                    Console.WriteLine(uf.IsSameSet(q.x, q.y) ? 1 : 0);
                }
            }

            //---------------------------------
        }
    }

    public class UnionFind{
        private readonly int[] _rank;
        private readonly int[] _p;

        public UnionFind(int size){
            _rank = new int[size];
            _p = new int[size];

            for(var i = 0; i < size; i++){
                _rank[i] = 0;
                _p[i] = i;
            }
        }

        public void Unite(int x, int y){
            x = FindSet(x);
            y = FindSet(y);

            if(_rank[x] > _rank[y]) _p[y] = x;
            if(_rank[x] < _rank[y]) _p[x] = y;
            if(_rank[x] == _rank[y]){
                _p[x] = y;
                _rank[y]++;
            }
        }

        public bool IsSameSet(int x, int y){
            return FindSet(x) == FindSet(y);
        }

        public int FindSet(int x){
            if(_p[x] == x) return x;
            return _p[x] = FindSet(_p[x]);
        }
    }

    public class StreamReader{
        private readonly char[] _c = {' '};
        private int _index = -1;
        private string[] _input = new string[0];
        private readonly System.IO.StreamReader _sr = new System.IO.StreamReader(Console.OpenStandardInput());

        public T Next<T>(){
            if(_index == _input.Length - 1){
                _index = -1;
                while(true){
                    string rl = _sr.ReadLine();
                    if(rl == null){
                        if(typeof(T).IsClass) return default(T);
                        return (T)typeof(T).GetField("MinValue").GetValue(null);
                    }
                    if(rl != ""){
                        _input = rl.Split(_c, StringSplitOptions.RemoveEmptyEntries);
                        break;
                    }
                }
            }
            return (T)Convert.ChangeType(_input[++_index], typeof(T), System.Globalization.CultureInfo.InvariantCulture);
        }

        public T[] Next<T>(int x){
            var ret = new T[x];
            for(var i = 0; i < x; ++i) ret[i] = Next<T>();
            return ret;
        }

        public T[][] Next<T>(int y, int x){
            var ret = new T[y][];
            for(var i = 0; i < y; ++i) ret[i] = Next<T>(x);
            return ret;
        }
    }
}