Problem:
Score : 100 points

Problem Statement

You are given an undirected graph with N vertices and 0 edges. Process Q queries of the following types.

0 u v: Add an edge (u, v).

1 u v: Print 1 if u and v are in the same connected component, 0 otherwise.

Constraints

1 \leq N \leq 200,000

1 \leq Q \leq 200,000

0 \leq u_i, v_i \lt N

Input

Input is given from Standard Input in the following format:

N Q
t_1 u_1 v_1
t_2 u_2 v_2
:
t_Q u_Q v_Q

出力

For each query of the latter type, print the answer.

Sample Input 1

4 7
1 0 1
0 0 1
0 2 3
1 0 1
1 1 2
0 0 2
1 1 3

Sample Output 1

0
1
0
1

Solution in Java (OpenJDK 1.8.0) (judge verdict: Accepted)

import java.util.*;
import java.io.*;

public class Main {
    public static void main(String[] args) throws Exception {
        FastScanner sc = new FastScanner(System.in);
        PrintWriter pw = new PrintWriter(System.out);
        int n = sc.nextInt();
        DSU dsu = new DSU(n);
        int q = sc.nextInt();
        for(int i = 0; i < q; i++){
            int t = sc.nextInt();
            int a = sc.nextInt();
            int b = sc.nextInt();
            if(t == 0){
                dsu.merge(a, b);
            }else if(t == 1){
                if(dsu.same(a, b)){
                    pw.println(1);
                }else{
                    pw.println(0);
                }
            }
        }
        pw.close();
    }
}

class DSU{
    private int n;
    private int[] parentOrSize;
    
    public DSU(int n){
        this.n = n;
        this.parentOrSize = new int[n];
        Arrays.fill(parentOrSize,-1);
    }
    
    int merge(int a, int b){
        if(!(0 <= a && a < n) || !(0 <= b && b < n)){
            // この式が成立しない物は動作しません。
            return -1;
        }
        int x = leader(a);
        int y = leader(b);
        if(x == y) return x;
        if(-parentOrSize[x] < -parentOrSize[y]){
            int tmp = x;
            x = y;
            y = tmp;
        }
        parentOrSize[x] += parentOrSize[y];
        parentOrSize[y] = x;
        return x;
    }
    
    boolean same(int a, int b){
        if(!(0 <= a && a < n) || !(0 <= b && b < n)){
            // この式が成立しない物は動作しません。
            return false;
        }
        return leader(a) == leader(b);
    }
    
    int leader(int a){
        if (parentOrSize[a] < 0){
            return a;
        }else{
            parentOrSize[a] = leader(parentOrSize[a]);
            return parentOrSize[a];
        }
    }

    int size(int a) {
        if(!(0 <= a && a < n)){
            // この式が成立しない物は動作しません。
            return -1;
        }
        return -parentOrSize[leader(a)];
    }
    
    ArrayList<ArrayList<Integer>> groups(){
        int[] leaderBuf = new int[n];
        int[] groupSize = new int[n];
        for(int i = 0; i < n; i++){
            leaderBuf[i] = leader(i);
            groupSize[leaderBuf[i]]++;
        }
        ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>();
        for(int i = 0; i < n; i++){
            result.add(new ArrayList<>());
        }
        for(int i = 0; i < n; i++){
            result.get(leaderBuf[i]).add(i);
        }
        return result;
    }
}

class FastScanner {
    private BufferedReader reader = null;
    private StringTokenizer tokenizer = null;
    public FastScanner(InputStream in) {
        reader = new BufferedReader(new InputStreamReader(in));
        tokenizer = null;
    }

    public String next() {
        if (tokenizer == null || !tokenizer.hasMoreTokens()) {
            try {
                tokenizer = new StringTokenizer(reader.readLine());
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        return tokenizer.nextToken();
    }

    public String nextLine() {
        if (tokenizer == null || !tokenizer.hasMoreTokens()) {
            try {
                return reader.readLine();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        return tokenizer.nextToken("\n");
    }

    public long nextLong() {
        return Long.parseLong(next());
    }

    public int nextInt() {
        return Integer.parseInt(next());
    }

    public double nextDouble() {
         return Double.parseDouble(next());
    }
    
    public String[] nextArray(int n) {
        String[] a = new String[n];
        for (int i = 0; i < n; i++)
            a[i] = next();
        return a;
    }

    public int[] nextIntArray(int n) {
        int[] a = new int[n];
        for (int i = 0; i < n; i++)
            a[i] = nextInt();
        return a;
    }

    public long[] nextLongArray(int n) {
        long[] a = new long[n];
        for (int i = 0; i < n; i++)
            a[i] = nextLong();
        return a;
    } 
}