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++ (GCC 9.2.1 with AC Library v1.1) (judge verdict: Runtime Error)

#include<bits/stdc++.h>
#include<atcoder/all>
using namespace std;

#define lli long long
#define all(i) i.begin(),i.end()
#define rall(i) i.rbegin(),i.rend()
#define rep0(i,j) for(int i=0;i<j;i++)
#define rep1(i,j) for(int i=1;i<=j;i++)
#define rep0d(i,j) for(int i=j-1;i>=0;i--)
#define MOD 1000000007
#define MAX (lli)1e12 
using p=pair<lli,lli>;

class Graph{
  int V;
  vector<list<p>> adj; 
  const int INF = (int)1e6;

  public: 
  Graph(lli V): adj(V){ 
    this->V = V; 
  } 

  void addEdge(int u, int v, int w){ 
    adj[u].push_back(make_pair(v, w)); 
  } 

  lli edgeNum(){
    lli sum=0;
    rep0(i,V)sum+=adj[i].size();
    return sum;
  }

  bool route(lli from, lli to){//vec[i]==j: j->iっていうもとに戻れる道がある
    vector<lli> vec(V, -1);
    dfs(1,from,vec);
    return vec[to] >= 0;
  }

  void dfs(lli ed, lli num, vector<lli>& vec){
    for(auto e: adj[num]){
      if(vec[e.first] != -1)continue;
      vec[e.first] = num;
      dfs(ed+1, e.first, vec);
    }
  }

  vector<int> bfs(int n){
    queue<int> q;
    vector<int> vec(V,-1);

    q.push(n);
    vec[n]=0;
    while(!q.empty()){
      int p=q.front();
      q.pop();
      for(auto e:adj[p]){
        if(vec[e.first]==-1){
          q.push(e.first);
          vec[e.first] = e.second + vec[p];
        }
      }
    }
    return vec;
  }

  vector<int> shortestPath(int src){ 
    priority_queue< p, vector <p> , greater<p> > pq; 
  
    vector<int> dist(V, INF); 
    pq.push(make_pair(0, src)); 
    dist[src] = 0; 
  
    while (!pq.empty()) { 
        int u = pq.top().second; 
        pq.pop(); 
  
        list<p>::iterator i; 
        for (auto i = adj[u].begin(); i != adj[u].end(); ++i) { 
            int v = i->first; 
            int weight = i->second; 
  
            if (dist[v] > dist[u] + weight) { 
                dist[v] = dist[u] + weight; 
                pq.push(make_pair(dist[v], v)); 
            } 
        } 
    } 
    for(int i=0;i<V;i++)if(dist[i]==INF)dist[i]=-1;
    return dist;
  } 

};

struct UF{
    vector<int> par,size;

    UF(int N) : par(N), size(N, 1){
        rep0(i,N)par[i] = i;
    }

    int root(int x){
        if (par[x] == x) return x;
        return par[x] = root(par[x]);
    }

    void unite(int x, int y){
        int rx = root(x);
        int ry = root(y);
        if(rx == ry) return;
        par[rx] = ry;
        size[rx] += size[ry];
    }

    bool same(int x, int y){
        int rx = root(x);
        int ry = root(y);
        return rx == ry;
    }

    int getSize(int x){
        return size[x];
    }
};
struct BIT{
  vector<lli> tab;//bit table
  BIT(int n):tab(n+1){
    rep0(i,n+1)tab[i]=0;
  }

  void add(int p, lli num){
    for(++p;p<tab.size();p+=p&-p)tab[p]+=num;
  }

  lli sum(int p){//from 0 to p-1: 0-indexedppoi
    lli ans=0;
    for(++p;p>0;p-=p&-p)ans+=tab[p];
    return ans;
  }

  void debug(){
    rep0(i,tab.size())cout << tab[i] << ' ';
    cout << endl;
  }
};

struct BIT_mod{
  vector<lli> tab;//bit table
  lli mod = 998244353;
  BIT_mod(int n):tab(n+1){
    rep0(i,n+1)tab[i]=0;
  }

  void add(int p, lli num){
    for(++p;p<tab.size();p+=p&-p){
      tab[p]+=num;
      tab[p]%=mod;
      tab[p]+=mod;
      tab[p]%=mod;
    }
  }

  lli sum(int p){//from 0 to p
    lli ans=0;
    for(++p;p>0;p-=p&-p){
      ans+=tab[p];
      ans%=mod;
      ans+=mod;
      ans%=mod;
    }
    return ans;
  }

  void debug(){
    rep0(i,tab.size())cout << tab[i] << ' ';
    cout << endl;
  }
};

struct Mod {
  lli mod, size;
  vector<lli> primes, inv, num;

  Mod(lli m, lli s):num(s+1, 0), inv(s+1, 0){
    mod = m;
    size = s;

    //素因数分解
    num[1] = 1;
    for(lli i=2; i<=size; i++){
      bool prime = false;
      if(num[i] == 0){
        num[i] = i;
        primes.push_back(i);
        prime = true;
      }

      for(auto e: num){
        if(e > num[i] || e*num[i] > size) break;
        num[num[i]*e] = e;
      }

      if(prime)num[i] = 0;
    }

    //逆元列挙
    for(lli i=2; i<=size; i++){
      if(num[i] == 0){
        lli m = (mod-1) >> 1;
        lli rec = i, ret = 0;
        while(m > 0){
          rec *= rec;
          rec %= mod;
          if(m&1){
            ret+=rec;
            ret%=mod;
          }
          m >>= 1;
        }
        inv[i] = ret;
      }else{
        inv[i]=(inv[i/num[i]]*inv[num[i]])%mod;
      }
    }
  }

};
 
//pairに関するもの
lli sum(p c){
  return (c.first + c.second);
}
p operator-(const p & l,const p & r) {   
    return {l.first-r.first,l.second-r.second};                                    
}
bool cmpf(const pair<lli, lli> left, const pair<lli, lli> right) {
    return left.first < right.first;
}
bool cmps(const pair<lli, lli> left, const pair<lli, lli> right) {
    return left.second < right.second;
}
 
lli gcd(lli a, lli b){
    if(a < b)return gcd(b, a);
    lli temp;
    while((temp = a%b)){
        a=b;
        b=temp;
    }
    return b;
}

struct nCr{
  vector<lli> f, rf, r;
  nCr(lli num): f(num+1), rf(num+1), r(num+1){
      f[0] = rf[0] = rf[1] = r[1] = 1;
      rep1(i, num) f[i] = (f[i - 1] * i) % MOD;
      for(int i=2;i<=num;i++){
        r[i] = r[MOD%i] * (MOD - MOD/i)%MOD;
        rf[i] = r[i]*rf[i-1]%MOD;
      }
  }
    
  lli C(lli n, lli k) {
      if(k > n || k < 0)return 0;
      lli a = f[n];
      lli b = rf[n-k];
      lli c = rf[k];
   
      lli bc = (b * c) % MOD;
      return (a * bc) % MOD;
  }
};


int main(){
  lli n, m ;
  cin >> n >> m;
  atcoder::dsu d(n);
  rep0(i,m){
    lli a, b;
    cin >> a >> b;
    d.merge(a,b);
  }

  cout << d.groups().size()-1;

}