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 Rust (1.42.0) (judge verdict: Accepted)

use std::io::*;
use std::str::FromStr;
use std::collections::HashSet;

//https://qiita.com/tubo28/items/e6076e9040da57368845
fn read<T: FromStr>() -> T {
    let stdin = stdin();
    let stdin = stdin.lock();
    let token: String = stdin
        .bytes()
        .map(|c| c.expect("failed to read char") as char)
        .skip_while(|c| c.is_whitespace())
        .take_while(|c| !c.is_whitespace())
        .collect();
    token.parse().ok().expect("failed to parse token")
}

// UnionFind
// coding: https://youtu.be/TdR816rqc3s?t=726
// comment: https://youtu.be/TdR816rqc3s?t=6822
#[derive(Debug)]
struct UnionFind {
    //ノード情報のベクトル。
    //各ノードは親のノードを指す。
    //根なら木のサイズを負にして入れる。
    d: Vec<isize>,
}

impl UnionFind {
    //コンストラクタ dをn個の要素でそれぞれサイズ-1で初期化
    fn new(n: usize) -> UnionFind {
        UnionFind { d: vec![-1; n] }
    }

    //ノード番号を引数にとり
    //属する木のグループ番号を返す
    //グループ番号は属する木の根のノード番号
    fn find(&mut self, x: isize) -> isize {
        let u_x = x as usize;
        //負値であれば、根である
        if self.d[u_x] < 0 {
            x
        } else {
            //再帰的に根を探索し、各ノードの根の番号を張り替える（経路縮約）
            self.d[u_x] = self.find(self.d[u_x]);
            self.d[u_x]
        }
    }

    //木の併合
    //木のサイズが小さい方を大きい方にくっつける
    //長いものにまかれにいく
    //木が深くならなくなる
    fn unite(&mut self, x: isize, y: isize) -> bool {
        //所属するグループの検索
        let mut x = self.find(x);
        let mut y = self.find(y);
        let mut u_x = x as usize;
        let mut u_y = y as usize;
        //すでに所属グループが同じ
        if x == y {
            return false;
        }
        //xを大きいサイズのグループに設定する
        if self.d[u_x] > self.d[u_y] {
            std::mem::swap(&mut x, &mut y);
            std::mem::swap(&mut u_x, &mut u_y);
        }
        //大きいグループxに小さいグループyのサイズを加算する
        self.d[u_x] += self.d[u_y];
        //グループyの親をxにするくっつける
        self.d[u_y] = x;
        return true;
    }

    //ノードxとノードyが同じグループか判定する
    fn same(&mut self, x: isize, y: isize) -> bool {
        self.find(x) == self.find(y)
    }
    //所属するグループのサイズを返す
    fn size(&mut self, x: isize) -> isize {
        let root = self.find(x);
        -self.d[root as usize]
    }
}

fn main() {
    let n: usize = read();
    let m: usize = read();
    let mut tree = UnionFind::new(n);

    for _ in 0..m {
        let a:isize = read();
        let b:isize = read();
        tree.unite(a-1 , b-1);
    }
    let mut set = HashSet::new();
    for i in 0..n{
        set.insert(tree.find(i as isize));
    }
    println!("{}",set.len()-1);
}