#pragma GCC target ("sse4.2")
#include<bits/stdc++.h>

using namespace std;

#define F first
#define S second
#define PB push_back
#define ln "\n"
#define forn(i,e) for(ll i=0; i<e; i++)
#define forsn(i,s,e) for(ll i=s; i<e; i++)
#define rforn(i,e) for(ll i=e; i>=0; i--)
#define rforsn(i,e,s) for(ll i=e; i>=s; i--)
#define vasort(v)         sort(v.begin(), v.end());
#define vdsort(v)         sort(v.begin(), v.end(),greater<ll>());
#define fio ios_base::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL)
#define     mem(a,b)        memset(a,b,sizeof(a))
#define     sz(x)           ((int)size(x))
#define     EB              emplace_back
#define     flush           fflush(stdout)
#define out1(x1) cout << x1 << ln
#define out2(x1,x2) cout << x1 << " " << x2 << endl
#define out3(x1,x2,x3) cout << x1 << " " << x2 << " " << x3 << endl
#define out4(x1,x2,x3,x4) cout << x1 << " " << x2 << " " << x3 << " " << x4 << ln
#define all(d) d.begin(), d.end()
#define unordered_set(T) unordered_set<T, custom_hash>
#define unordered_map(T1, T2) unordered_map<T1, T2, custom_hash>

#define in1(x1) cin >> x1
#define in2(x1,x2) cin >> x1 >> x2
#define in3(x1,x2,x3) cin >> x1 >> x2 >> x3
#define in4(x1,x2,x3,x4) cin >> x1 >> x2 >> x3 >> x4

#define arrin(a, n) forn(i, n) cin >> a[i];
#define arrout(a,n) forn(i,n) {cout << a[i] << " ";} cout << ln;



/* ---------------- IO ----------------*/

namespace IO
{
    const int BUFFER_SIZE = 1 << 15;
    char input_buffer[BUFFER_SIZE];
    int input_pos = 0, input_len = 0;
    char output_buffer[BUFFER_SIZE];
    int output_pos = 0;
    char number_buffer[100];
    uint8_t lookup[100];
    void _update_input_buffer()
    {
        input_len = fread(input_buffer, sizeof(char), BUFFER_SIZE, stdin);
        input_pos = 0;
        if (input_len == 0)
            input_buffer[0] = EOF;
    }
    inline char next_char(bool advance = true)
    {
        if (input_pos >= input_len)
            _update_input_buffer();

        return input_buffer[advance ? input_pos++ : input_pos];
    }

    template <typename T>
    inline void read_int(T &number)
    {
        bool negative = false;
        number = 0;

        while (!isdigit(next_char(false)))
            if (next_char() == '-')
                negative = true;

        do
        {
            number = 10 * number + (next_char() - '0');
        } while (isdigit(next_char(false)));

        if (negative)
            number = -number;
    }

    template <typename T, typename... Args>
    inline void read_int(T &number, Args &... args)
    {
        read_int(number);
        read_int(args...);
    }

    void _flush_output()
    {
        fwrite(output_buffer, sizeof(char), output_pos, stdout);
        output_pos = 0;
    }

    inline void write_char(char c)
    {
        if (output_pos == BUFFER_SIZE)
            _flush_output();

        output_buffer[output_pos++] = c;
    }

    template <typename T>
    inline void write_int(T number, char after = '\0')
    {
        if (number < 0)
        {
            write_char('-');
            number = -number;
        }
        int length = 0;
        while (number >= 10)
        {
            uint8_t lookup_value = lookup[number % 100];
            number /= 100;
            number_buffer[length++] = (lookup_value & 15) + '0';
            number_buffer[length++] = (lookup_value >> 4) + '0';
        }
        if (number != 0 || length == 0)
            write_char(number + '0');
        for (int i = length - 1; i >= 0; i--)
            write_char(number_buffer[i]);
        if (after)
            write_char(after);
    }
    void IOinit()
    {
        // Make sure _flush_output() is called at the end of the program.
        bool exit_success = atexit(_flush_output) == 0;
        assert(exit_success);
        for (int i = 0; i < 100; i++)
            lookup[i] = (i / 10 << 4) + i % 10;
    }
} // namespace IO

using namespace IO;



/* ---------------- typedefs ----------------*/
typedef long long ll;
typedef long double ld;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef vector<int> vi;
typedef vector<ll> vll;



/* ---------------- utility functions ---------------- */

int dr[] = {0,1,-1,0,1,-1,1,-1};
int dc[] = {1,0,0,-1,1,-1,-1,1};
int drr[] = {-2,-1,0,1,2};
int dcc[] = {-2,-1,0,1,2};
bool chk(int a, int b, int n, int m) {
        return 0 <= a && a < n && 0 <= b && b < m;
}

ll exp(ll n, ll m, ll md){
        ll a = 1;
        while (m > 0){
                if (m&1) a = (a * n%md) % md;
                m /= 2;
                n = (n*n) % md;
        }
        return a % md;
}

ll expm(ll n, ll m){
    ll a = 1;
    while (m > 0){
        if(a < 0 or a >= (1e18 + n-1)/n) {
            return -1;
        }
        if (m&1) a = (a * n);
        m /= 2;
        n = (n*n);
    }
    return a;
}

void disp(vi v){
        for(auto u:v)
                cout<<u<<" ";
        cout<<"\n";
}
void disp(vll v){
    for(auto u:v)
        cout<<u<<" ";
    cout<<endl;
}

int getSqr(int x){
        if(x < 0)
                return -1;
        int l = sqrt(x);
        for (int i = -2; i <= 2; ++i)
                if (l + i >= 0 && (l + i) * (l + i) == x)
                        return l;
        return -1;
}

const int NPRR = 1e7;
vi lp;
vector<int> prr;
void prfac(int n = NPRR){
        assert(n <= NPRR);
        lp.assign(n+1, 0);
        int i;
        for (i = 2;i <= n;++i) {
                if (lp[i] == 0) {
                        lp[i] = i;
                        prr.push_back(i);
                }
                for (int u: prr) {
                        if(i * u > n || u > lp[i]) break;
                        lp[i * u] = u;
                }
        }
}


bool check_composite_for_prime_function(ll n, ll a, ll d, int s){
        ll x = exp(a, d, n);
        if (x == 1 || x == n-1) return false;
        for(int r = 1;r < s;++r){
                x = x * x%n;
                x %= n;
                if(x == n-1) return false;
        }
        return true;
}
bool prime(ll n){
        if(n < 4) return n == 2 || n == 3;
        if (!(n&1)) return false;
        int s = 0;
        ll d = n-1;
        while(!(d&1)){
                d >>= 1;
                s++;
        }
        for(int a : {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37}){
                if(n == a) return true;
                if(check_composite_for_prime_function(n, a, d, s)) return false;
        }
        return true;
}

ll binomialCoeff(ll n, ll k)
{
    ll res = 1;

    // Since C(n, k) = C(n, n-k)
    if (k > n - k)
        k = n - k;

    // Calculate value of
    // [n * (n-1) *---* (n-k+1)] / [k * (k-1) *----* 1]
    for (ll i = 0; i < k; ++i) {
        res *= (n - i);
        res /= (i + 1);
    }

    return res;
}
/* custom hash for unordered map */
struct custom_hash {
    static uint64_t splitmix64(uint64_t x) {
            // http://xorshift.di.unimi.it/splitmix64.c
            x += 0x9e3779b97f4a7c15;
            x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
            x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
            return x ^ (x >> 31);
    }

    size_t operator()(uint64_t x) const {
            static const uint64_t FIXED_RANDOM = chrono::steady_clock::now().time_since_epoch().count();
            return splitmix64(x + FIXED_RANDOM);
    }
};


inline void read(int &x)
{
    scanf("%d", &x);
}

auto random_address = [] { char *p = new char; delete p; return uint64_t(p); };

const uint64_t SEED = chrono::steady_clock::now().time_since_epoch().count() * (random_address() | 1);
mt19937_64 rng(SEED);


/* ---------------- constants ---------------- */
const ll MAXn=2e5 + 33,MAXlg=__lg(MAXn)+2;
const ll MOD=1000000007;
const ll INF=ll(1e15);

/* ---------------- gcd_extended ---------------- */
/*
 * CAREFUL: Overflow at x *= c/g out of 10**18
 * Lookout for A = 0 or B = 0
 */
void shift(ll &x, ll& y, ll cnt, ll a, ll b) {
    x += cnt * b;
    y -= cnt * a;
}
ll gcd(ll a, ll b, ll& x, ll& y) {
    if (b == 0) {
        x = 1;
        y = 0;
        return a;
    }
    ll x1, y1;
    ll d = gcd(b, a % b, x1, y1);
    x = y1;
    y = x1 - y1 * (a / b);
    return d;
}
bool give_range(ll a, ll b, ll c, ll mina, ll maxa, ll minb, ll maxb, ll &lx, ll &rx) {
    ll x, y;
    ll g = gcd(a, b, x, y);
    if(c % g != 0) return false;
//    out2(x, y);
    x *= c/g;
    y *= c/g;
//    out2(x, y);
    a /= g;
    b /= g;
    if(a == 0 || b == 0) {
        if(x >= mina && x <= maxa && y >= minb && y <= maxb) {
            lx = x;
            rx = x;
            return true;
        }
        return false;
    }
    ll sign_a = (a > 0 ? 1 : -1);
    ll sign_b = (b > 0 ? 1 : -1);
    ll lx1, lx2, rx1, rx2;
    {
        ll cnt = (mina - x)/b;
        shift(x, y, cnt, a, b);
        if(x < 0) shift(x, y, sign_a, a, b);
        if(x > maxa) {
            return false;
        }
//        out2(x, y);

        lx1 = x;
    }
    {
        ll cnt = (maxa - x)/b;
        shift(x, y, cnt, a, b);
//        out2(x, y);
        rx1 = x;
    }
    {
        ll cnt = -(minb - y)/a;
        shift(x,y, cnt, a, b);
        if(y < 0) shift(x,y,-sign_b, a, b);
        if(y > maxb) {
            return false;
        }
//        out2(x, y);

        lx2 = x;
    }
    {
        ll cnt = -(maxb - y)/a;
        shift(x, y, cnt, a, b);
//        out2(x, y);

        rx2 = x;
    }
    if(lx2 > rx2) swap(lx2, rx2);
//    out4(lx1, lx2, rx1, rx2);

    ll lxx = max(lx1, lx2);
    ll rxx = min(rx1, rx2);
    if(lxx > rxx) {
        return false;
    }
    lx = lxx;
    rx = rxx;
    return true;
}

/* ---------------- start of code ---------------- */


/*vector<set<int> > ad;
vi par;
vi lev;
vi maxdepth;
int n;
void dfs_for_par(int s, int parent, int level) {
    par[s] = parent;
    lev[s] = level;
    for(auto u: ad[s]) {
        if(u==parent) continue;
        dfs_for_par(u, s, level+1);
    }
}
int dfsmaxdepth(int s, int e) {
    int res = 0;
    for(auto u: ad[s]) {
        if(u == e) continue;
        dfsmaxdepth(u,s);
        res = max(res, maxdepth[u]);
    }
    maxdepth[s] = ++res;
    return res;
}
vi ans;
void dfs(int s, int e) {
    vi res(n+1, 0);
    for(auto u: ad[s]) {
        if(u == e) continue;
        res[0]++;
        res[maxdepth[u]+1]--;
    }
    for(auto u: ad[e]) {
        if(u == s or u == par[e]) continue;
        res[0]++;
        res[maxdepth[u] + 1]--;
    }
    forn(i, n) res[i+1] += res[i];
    forn(i, n+1) ans[i] = max(ans[i], res[i]);
    for(auto u: ad[s]) {
        if(u == e) continue;
        dfs(u, s);
    }
}
void go2() {
    cin >> n;
    ad.assign(n, {});
    par.assign(n,0);
    ans.assign(n,0);
    lev.assign(n,0);
    maxdepth.assign(n,0);
    forn(i, n-1) {
        int r,s;in2(r,s);
        r--;s--;
        ad[r].insert(s);
        ad[s].insert(r);
    }
    if(n == 2) {
        out2(2, 2);
        return;
    }
    dfs_for_par(0,0,0);
    dfsmaxdepth(0,0);


}

void go1() {
    int n;
    string s;cin >> s;
    n = s.size();
    int i = 0;
    if(n <=3) {
        cout << s[0] << ln;
        return;
    }
    string ans;
    while(i < n/2) {
        if(n % 4 > 0 and i >= (n/4 * 4) / 2) break;
        int cnt[3] = {0};
        cnt[s[i] - 'a']++;
        cnt[s[i+1] - 'a']++;
        cnt[s[n-i-1] - 'a']++;
        cnt[s[n-i-2] - 'a']++;
        forn(j, 3) {
            if(cnt[j] > 1) {
                ans += (char)(j + 'a');
                break;
            }
        }
        i+=2;
    }

    string anss = ans;
    reverse(all(anss));
    if(n % 4 > 0) {
        ans += s[n/2];
    }
    ans += anss;
    assert(ans.size() >= n/2);
    cout << ans << ln;


}
ll md = 998244353;
void go3() {
    ll n;cin >> n;
    ll q;cin >> q;
    ll a[n];
    forn(i, n) cin >> a[i];
    if(n == 1) {
        cout << a[0] << ln;
        return;
    }
    if(n == 2) {
        cout << max(a[0], a[1]) << ln;
        return;
    }
    ll o[n], e[n];
    o[0] = a[0];
    e[0] = -1e9-7;
    o[1] = a[1];
    e[1] = a[0] - a[1];
    ll me = max(e[0], e[1]);
    ll mo = max(o[0], o[1]);
    ll prev[n];
    prev[0] = -1;
    prev[1] = -1;
    forsn(i, 2, n) {

        o[i] = max(a[i], me + a[i]);
        e[i] = mo - a[i];
        me = max(me, e[i]);
        mo = max(mo, o[i]);
    }
    cout << max(mo, me) << ln;
}
ll c(ll n, ll k) {
    if(n <= 0 or k > n) {
        return 0;
    }
    ll res = 1;
    k = min(k, n - k);
    forn(i, k) {
        res = (res * (ll)(n - i)) % md;
        res /= (ll)(i + 1);
        res %= md;
    }
    return res;
}*/
vector<set<ll>> ad;
bool vis[200005];
void dfs(int s) {
    if(vis[s])return;
    vis[s] = true;
    for(auto u: ad[s]) {
        dfs(u);
    }
}

void go4() {
    int n;cin>>n;
    int m;cin >> m;
    ad.assign(n, {});
    forn(i,m) {
        int a, b;in2(a, b);a--;b--;
        ad[a].insert(b);
        ad[b].insert(a);
    }
    ll ans = 0;
    forn(i, n) {
        if(vis[i]) continue;
        ans++;
        dfs(i);
    }
    cout << --ans << ln;

}


int main(){
    fio;
    fflush(stdout);
    cout<<fixed<<setprecision(0);
    cerr<<fixed<<setprecision(10);

    //freopen("input.txt","r",stdin);freopen("output.txt","w",stdout);

    ll tt = 1;

/*

    cin >> tt;
    ll t = tt;

    //*/
    //forn(i, 100) cout << fac[i] << " ";

    auto start  = std::chrono::high_resolution_clock::now();

    while(tt--){
        //cout << "Case #" << t - tt << ": ";
        go4();
    }
    auto stop = std::chrono::high_resolution_clock::now();
    auto duration = std::chrono::duration_cast<std::chrono::nanoseconds>(stop - start);
    //cerr << "Time taken : " << ((long double)duration.count())/((long double) 1e9) <<"s "<< endl;
    return 0;
}
/* ---------------- end of code ---------------- */



Measured memory_bytes: 18220