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 C# (Mono-csc 3.5.0) (judge verdict: Accepted)

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Text.RegularExpressions;
using System.Numerics;using static System.Math;
namespace _NS
{
    class PR
    {
        static void Main()
        {
            var NM = CinTAr;
            var U = new UnionFind(NM[0]);
            AFOR(NM[1], _ =>
            {
                var ab = CinTAr;
                U.Unite(ab[0] - 1, ab[1] - 1);
            });
            var res = new HashSet<int>();
            AFOR(NM[0], i => res.Add(U.Root(i)));
            Cout = res.Count - 1;


            Console.ReadLine();
        } //main
        #region LIBRARY
        static int MOD10_9_7 = 1000000000 + 7, MOD9982 = 998244353;
        static int GrARXY(int x, int y, int wid) { return y * wid + x; }
        static int[] GrXY(int arxy, int wid) { return new int[] { arxy % wid, arxy / wid }; }
        static int GetDigits(long n) { return (int)Floor(Log10(n)) + 1; }
        static int GetNumByDigit(long n, int d) { return (int)((n / ((int)Pow(10, d - 1))) % 10); }
        static long Loop(long n, long max) { if (n > max) { return n % (max + 1); } else if (n < 0) { return max - (-n - 1) % (max + 1); } else { return n; } }
        static int Loop(int n, int max) { return (int)Loop((long)n, max); }
        static long PW10(int n) { return (long)Pow(10, n); }
        static long GCD(long a, long b) { if (a < b) { return GCD(b, a); } if (a % b == 0) { return b; } else { return GCD(b, a % b); } }
        static long LCM(long a, long b) { return a * b / GCD(a, b); }
        static void Swap<T>(ref T a, ref T b) { T t = a; a = b; b = t; }
        static void SwapArE<T>(T[] a, int i, int j) { T t = a[i]; a[i] = a[j]; a[j] = t; }
        static void SwapLiE<T>(List<T> a, int i, int j) { T t = a[i]; a[i] = a[j]; a[j] = t; }
        static bool IsInt(double d) { return (long)d == d; }
        static string Cin { get { return Console.ReadLine(); } }
        static string[] CinAr { get { return Cin.Split(' ').Where(x => x != "").ToArray(); } }
        static int CinT { get { return S2I(Cin); } }
        static int[] CinTAr { get { return CinAr.Select(S2I).ToArray(); } }
        static long CinL { get { return S2L(Cin); } }
        static long[] CinLAr { get { return CinAr.Select(S2L).ToArray(); } }
        static double CinD { get { return S2D(Cin); } }
        static double[] CinDAr { get { return CinAr.Select(S2D).ToArray(); } }
        static int S2I(string s) { return int.Parse(s); }
        static long S2L(string s) { return long.Parse(s); }
        static double S2D(string s) { return double.Parse(s); }
        static object Cout { set { Console.WriteLine(value); } }
        static object CoutW { set { Console.Write(value); } }
        static bool CoutYN { set { if (value) { Cout = "Yes"; } else { Cout = "No"; } } }
        static bool CoutGB { set { if (value) { Cout = "Good"; } else { Cout = "Yes"; } } }
        static string RevStr(string s) { return new string(s.Reverse().ToArray()); }
        static void AFOR(int m, Action<int> ActI) { for (int i = 0; i < m; i++) { ActI(i); } }
        static void AFOR(int m, Action Act) { AFOR(m, i => Act()); }
        static long[] Divisors(long n)
        {
            if (n == 1) { return new long[] { 1 }; } List<long> r = new List<long>() { 1, n };
            for (long i = 2; i <= Sqrt(n); i++) { if (n % i == 0) { r.Add(i); long f = n / i; if (f != i) { r.Add(f); } } }
            return r.ToArray();
        }
        static IEnumerable<decimal> PrimeFactors(decimal n)
        {
            decimal i = 2, t = n; while (i * i <= n) { if (t % i == 0) { t /= i; yield return i; } else { i++; } }
            if (t != 1) { yield return t; }
        }
        static bool IsPrime(long n) { if (n == 1) { return false; } for (long i = 2; i <= Sqrt(n) + 1; i++) { if (n % i == 0) { return false; } } return true; }
        static void CoutPaAr<Type>(IEnumerable<Pair<Type>> p) { CoutAr(p.Select(x => $"({x.a}, {x.b}, {x.c})")); }
        static void CoutPaAr<Type>(IEnumerable<RefPair<Type>> p) { CoutAr(p.Select(x => $"({x.a}, {x.b}, {x.c})")); }
        static void CoutAr<Type>(IEnumerable<Type> t) { Cout = string.Join(" ", t); }
        static long nCr(int n, int r) { return nPr(n, r) / Factorial(r); }
        static long nPr(int n, int r) { return FactorDiv(n, n - r); }
        static long FactorDiv(int t, int d) { long r = 1; for (int i = t; i > d; i--) { r *= i; } return r; }
        static long Factorial(int i) { if (i <= 1) { return 1; } return i * Factorial(i - 1); }
        #endregion
    }
    struct Pair<T>
    {
        public T a, b, c;
        public Pair(T _a, T _b = default, T _c = default) { a = _a; b = _b; c = _c; }
    }
    class RefPair<T>
    {
        public T a, b, c;
        public RefPair(T _a, T _b = default, T _c = default) { a = _a; b = _b; c = _c; }
    }
    class UnionFind
    {
        private readonly List<int> r;
        public UnionFind(int n) { r = Enumerable.Repeat(-1, n).ToList(); }
        public int Root(int x) { if (r[x] < 0) return x; return r[x] = Root(r[x]); }
        public bool Unite(int x, int y)
        {
            x = Root(x); y = Root(y); if (x == y) return false;
            if (r[x] > r[y]) { var temp = x; x = y; y = temp; } r[x] += r[y]; r[y] = x; return true;
        }
        public int Size(int x) { return -r[Root(x)]; }
    }
}