Problem:
Score : 300 points

Problem Statement

There are N cities numbered 1 through N, and M bidirectional roads numbered 1 through M.
Road i connects City A_i and City B_i.

Snuke can perform the following operation zero or more times:

Choose two distinct cities that are not directly connected by a road, and build a new road between the two cities.

After he finishes the operations, it must be possible to travel from any city to any other cities by following roads (possibly multiple times).

What is the minimum number of roads he must build to achieve the goal?

Constraints

2 \leq N \leq 100,000

1 \leq M \leq 100,000

1 \leq A_i < B_i \leq N

No two roads connect the same pair of cities.

All values in input are integers.

Input

Input is given from Standard Input in the following format:

N M
A_1 B_1
:
A_M B_M

Output

Print the answer.

Sample Input 1

3 1
1 2

Sample Output 1

1

Initially, there are three cities, and there is a road between City 1 and City 2.

Snuke can achieve the goal by building one new road, for example, between City 1 and City 3.
After that,

We can travel between 1 and 2 directly.

We can travel between 1 and 3 directly.

We can travel between 2 and 3 by following both roads (2 - 1 - 3).

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

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;

public class Main {
    public static void main(String[] args) {
        MyScanner sc = new MyScanner();

        int n = sc.nextInt();
        int m = sc.nextInt();

        UnionFind unifin = new UnionFind(n);
        for (int i = 0; i < m; i++) {
            int a = sc.nextInt()-1;
            int b = sc.nextInt()-1;

            unifin.unite(a, b);
        }

        int ans = unifin.count() - 1;
        System.out.println(ans);
    }

    static class UnionFind {
        // Parents[i]:iの親の番号 or 根だった場合、ついているノードの数N(-N)
        static List<Integer> Parents = new ArrayList<>();

        // 最初はすべてが根であるとして初期化
        public UnionFind(int N) {
            for (int i = 0; i < N; i++) {
                Parents.add(-1);
            }
        }

        // データが属する木の根を再帰で得る
        public int root(int x) {
            if (Parents.get(x) < 0)
                return x;
            Parents.set(x, root(Parents.get(x)));
            return Parents.get(x);
        }

        // xとyの木を併合
        public void unite(int x, int y) {
            int rx = root(x);
            int ry = root(y);
            if (rx == ry)
                return;

            // yの方が大きい場合は入れ替える
            if (size(rx) < size(ry)) {
                int tmp = rx;
                rx = ry;
                ry = tmp;
            }

            Parents.set(rx, Parents.get(rx) + Parents.get(ry));
            Parents.set(ry, rx);
        }

        // 2つのデータx, yが属する木が同じならtrueを返す
        public boolean same(int x, int y) {
            int rx = root(x);
            int ry = root(y);
            return rx == ry;
        }

        // 頂点の数を返す
        public int size(int x) {
            if (x >= 0)
                x = root(x);
            return Parents.get(x);
        }

        // 根の数
        public int count() {
            int cnt = 0;
            for (int i : Parents) {
                if (i < 0)
                    cnt++;
            }
            return cnt;
        }
    }

    static class MyScanner {
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in), 1 << 15);
        StringTokenizer tokenizer;

        String next() {
            try {
                while (tokenizer == null || !tokenizer.hasMoreTokens()) {
                    tokenizer = new StringTokenizer(reader.readLine());
                }
            } catch (IOException ignored) {
            }
            return tokenizer.nextToken();
        }

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

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