#include <bits/stdc++.h>
using namespace std;
long long n,m;
vector <long long> a,b;
vector <vector<long long>> city;
struct Node{
    int rootId = -1;
    int totalNodeNum = 1;

};
vector <vector<int>> friendList;
vector <vector<int>> blockList;
vector <Node> preFriendNodeList;

int getUnionMemberNum(int nodeId, vector<Node>&nodeV){
    #if 0
    cout << "getUnionMemberNum" << endl;
    cout << nodeId << endl;
    #endif
    int myLeafSize = nodeV[nodeId].totalNodeNum;
    if(nodeV[nodeId].rootId==-1){
        //cout << "pathA" << endl;
        //cout << myLeafSize << endl;
        return myLeafSize;
    }else{
        //cout << "pathB" << endl;
        int secondHandLeafSize = getUnionMemberNum(nodeV[nodeId].rootId,nodeV);
        //cout << secondHandLeafSize << endl;
        return (secondHandLeafSize);
    }
}
void listUpId(int nodeId, vector<int>&v){
    // cout << "listUpId" << endl;
    // cout << nodeId << endl;
    v.push_back(nodeId);
    if(preFriendNodeList[nodeId].rootId==-1){
        return;
    }else{
        listUpId(preFriendNodeList[nodeId].rootId,v);
        return;    
    }
}
bool isUnioned(int nodeId1, 
                    int nodeId2, 
                    vector<Node>&nodeV){
    vector <int> nodelist1;
    vector <int> nodelist2;
    listUpId(nodeId1,nodelist1);
    listUpId(nodeId2,nodelist2);
    for(int i = 0; i < nodelist1.size(); i++){
        if(nodelist1[i]==nodeId2){
            return true;
        }
    }
    for(int i = 0; i < nodelist2.size(); i++){
        if(nodelist2[i]==nodeId1){
            return true;
        }
    }
    return false;
}
int getRootId(int id, vector<Node>&nodeV){
    if(id==-1)return id;
    if(nodeV[id].rootId==-1)return id;
    return getRootId(nodeV[id].rootId,nodeV);
}
void makeUnion(int nodeId1, 
                    int nodeId2, 
                    vector<Node>&nodeV){
    #if 0
    cout << "makeUnion" << endl;
    #endif

    if(isUnioned(nodeId1,nodeId2,nodeV)){
        //すでにunion済み
        return;
    }

    Node *node1 = &(nodeV[nodeId1]);
    Node *node2 = &(nodeV[nodeId2]);

    //大きい方をrootとする。
    int leaf1 = getUnionMemberNum(nodeId1,nodeV);
    int leaf2 = getUnionMemberNum(nodeId2,nodeV);
    int rootId1 = getRootId(nodeId1,nodeV);
    int rootId2 = getRootId(nodeId2,nodeV);
    if(rootId1==rootId2){
        //すでにunion済み
        return;
    }

    if(leaf1>leaf2){
        nodeV[rootId2].rootId=rootId1;
        nodeV[rootId1].totalNodeNum+=leaf2;
    }else{
        nodeV[rootId1].rootId=rootId2;
        nodeV[rootId2].totalNodeNum+=leaf1;
    }
    #if 0
    cout << nodeId1 << endl;
    cout << nodeId2 << endl;
    cout << rootId1 << endl;
    cout << rootId2 << endl;
    cout << nodeV[rootId1].totalNodeNum << endl;
    cout << nodeV[rootId2].totalNodeNum << endl;
    cout << endl;
    #endif
}
bool isInclude(int id, vector <int> &v){
    for(int i = 0; i < v.size(); i++){
        if(id==v[i]){
            return true;
        }
    }
    return false;
}


int main(){
    cin >> n >> m;
    a = vector<long long>(m);
    b = vector<long long>(m);
    city = vector<vector<long long>>(n,vector<long long>());
    preFriendNodeList = vector <Node>(n);

    for(long long i = 0; i < m; i++){
        cin >> a[i] >> b[i];
        a[i]--;
        b[i]--;
        city[a[i]].push_back(b[i]);
        city[b[i]].push_back(a[i]);
        makeUnion(a[i],b[i],preFriendNodeList);
    }
    for(long long i = 0; i < n; i++){
        sort(city[i].begin(),city[i].end());
    }
    vector <long long > rootList;
    for(long long i = 0; i < n; i++){
        rootList.push_back(getRootId(i,preFriendNodeList));
    }
    sort(rootList.begin(),rootList.end());
    rootList.erase(unique(rootList.begin(),rootList.end()),rootList.end());
    cout << rootList.size() -1 << endl;
    #if 0
    cout << endl;
    for(long long i = 0; i < n; i++){
        cout << getRootId(i,preFriendNodeList) << endl;
    }
    #endif
    #if 0
    cout << endl;
    for(long long i = 0; i < n; i++){
        for(long long j = 0; j < city[i].size(); j++){
            cout << city[i][j] << " ";
        }
        cout << endl;
    }
    #endif
    return 0;
}

Measured memory_bytes: 12532