#include<bits/stdc++.h>
using namespace std;
struct Node
{
    int value,rank,kth;
    Node * son[2];
    Node(int value) : value(value) {
        son[0] = son[1] = NULL;
        rank = rand();
        kth = 1;
    }
    bool operator < (const Node & nod)const{
        return rank < nod.rank;
    }
    int cmp(int val){
        if(value == val)return -1;
        return val < value ? 0 : 1;
    }
    void maintain(){
        kth = 1;
        if(son[0] != NULL)kth += son[0] -> kth;
        if(son[1] != NULL)kth += son[1] -> kth;
    }
};
void rotate(Node * & o,int d)
{
    Node * k = o -> son[1 ^ d];
    o -> son[1 ^ d] = k -> son[d];
    k -> son[d] = o;
    o -> maintain();
    k -> maintain();
    o = k;
}
void insert(Node * & o,int val)
{
    if(o == NULL) o = new Node(val);
    else
    {
        int d = val < o -> value ? 0 : 1;
        insert(o -> son[d],val);
        if(o < o -> son[d])rotate(o,d ^ 1);
    }
    o -> maintain();///maintain inserted point's ancestors
}
void remove(Node * & o,int val)
{
  int d = o -> cmp(val);
  if(d == -1)
  {
    Node * u = o;
    if(o -> son[0] != NULL && o -> son[1] != NULL)
    {
      bool d2 = o -> son[0] < o -> son[1];
      rotate(o,d2 ^ 1);
      remove(o -> son[d2 ^ 1],val);
    }
    else
    {
      if(o -> son[0] == NULL)  o = o -> son[1];
      else    o = o -> son[0];
      //delete u; //todo:not delete
    }
  }
  else
    remove(o -> son[d],val);
  if(o != NULL)o -> maintain(); ///o maybe point to the NULL
}
const int MAXN = 1e5+20;
vector<int>vec[MAXN],vec2[MAXN];
int n,m,ans;
Node * froot;
int se[MAXN];
int find_kth(Node * & o,int k)
{
    if(o == NULL || o -> kth < k || k <= 0) return 0;
    int s = (o -> son[1] == NULL) ? 0 : o -> son[1] -> kth;
    if(k - 1 - s == 0)return o -> value;
    else if(k - 1 - s > 0)return find_kth(o -> son[0],k - 1 - s);
    else return find_kth(o -> son[1],k);
}
bool find(Node * o , int val){
  while(o != NULL)
  {
    int d = o -> cmp(val);
    if(d == -1)return true;
    o = o -> son[d];
  }
  return false;
}
void merge_tree(Node * & o,Node * & root)///have modify in this point
{
    if(o -> son[0] != NULL)merge_tree(o -> son[0],root);
    if(o -> son[1] != NULL)merge_tree(o -> son[1],root);
    insert(root,o -> value);
    delete o;
    o = NULL;  /// point o is deleted will point to random
}
void delete_tree(Node * & o)///have modified in this point
{
    if(o -> son[0] != NULL)delete_tree(o -> son[0]);
    if(o -> son[1] != NULL)delete_tree(o -> son[1]);
    delete o;
    o = NULL; /// make point point to NULL
}
int get_next(int u){
//  for (int i = 1; i < 10; ++i) {
//    cout << -find_kth(root[ro],i) << " ";
//  }
  //puts("");
  int l = 1,r=n,cnt=0;
  while (l < r){
    cnt++;
    int cm = (l+r)/2;
    int k = -find_kth(froot,cm);
    if(cm==k)l=cm+1;
    else r=cm;
  }
//  cout << u << " u v " << l << endl;
  if(!find(froot,-l)){
    insert(froot,-l);
  }
  else return -1;
  ans--;
  return l;
}
void dfs(int u){
  se[u]=1;
  for (auto v:vec[u]) {
    if(!se[v] && !find(froot,-v)){
      insert(froot,-v);
    }
  }
  while(true){
    int v = get_next(u);
    if(v == -1)break;
    vec2[u].push_back(v);
    se[v]=1;
  }
  for (auto v:vec[u]) {
    if(!se[v] && find(froot,-v)){
      remove(froot,-v);
    }
  }
  for (auto v:vec2[u]) {
    dfs(v);
  }

}
int main()
{
  scanf("%d%d",&n,&m);
  ans=n-1;
  for (int i = 0; i < m; ++i) {
    int u,v;
    scanf("%d%d",&u,&v);
    vec[u].push_back(v);
    vec[v].push_back(u);
  }
  for (int i = 1; i <= n; ++i) {
    if(!se[i]){
      insert(froot,-i);
      dfs(i);
    }
  }
  printf("%d\n",ans);
}


#include<bits/stdc++.h>
using namespace std;
struct Node
{
    int value,rank,kth;
    Node * son[2];
    Node(int value) : value(value) {
        son[0] = son[1] = NULL;
        rank = rand();
        kth = 1;
    }
    bool operator < (const Node & nod)const{
        return rank < nod.rank;
    }
    int cmp(int val){
        if(value == val)return -1;
        return val < value ? 0 : 1;
    }
    void maintain(){
        kth = 1;
        if(son[0] != NULL)kth += son[0] -> kth;
        if(son[1] != NULL)kth += son[1] -> kth;
    }
};
void rotate(Node * & o,int d)
{
    Node * k = o -> son[1 ^ d];
    o -> son[1 ^ d] = k -> son[d];
    k -> son[d] = o;
    o -> maintain();
    k -> maintain();
    o = k;
}
void insert(Node * & o,int val)
{
    if(o == NULL) o = new Node(val);
    else
    {
        int d = val < o -> value ? 0 : 1;
        insert(o -> son[d],val);
        if(o < o -> son[d])rotate(o,d ^ 1);
    }
    o -> maintain();///maintain inserted point's ancestors
}
void remove(Node * & o,int val)
{
  int d = o -> cmp(val);
  if(d == -1)
  {
    Node * u = o;
    if(o -> son[0] != NULL && o -> son[1] != NULL)
    {
      bool d2 = o -> son[0] < o -> son[1];
      rotate(o,d2 ^ 1);
      remove(o -> son[d2 ^ 1],val);
    }
    else
    {
      if(o -> son[0] == NULL)  o = o -> son[1];
      else    o = o -> son[0];
      delete u;
    }
  }
  else
    remove(o -> son[d],val);
  if(o != NULL)o -> maintain(); ///o maybe point to the NULL
}
const int MAXN = 1e5+20;
vector<int>vec[MAXN];
int fa[MAXN],n,m,num[MAXN],ans;
Node * root[MAXN];
set<int>se;
int findfa(int i)
{
    return fa[i] == i ? fa[i] : fa[i] = findfa(fa[i]);
}
int find_kth(Node * & o,int k)
{
    if(o == NULL || o -> kth < k || k <= 0) return 0;
    int s = (o -> son[1] == NULL) ? 0 : o -> son[1] -> kth;
    if(k - 1 - s == 0)return o -> value;
    else if(k - 1 - s > 0)return find_kth(o -> son[0],k - 1 - s);
    else return find_kth(o -> son[1],k);
}
bool find(Node * o , int val){
  while(o != NULL)
  {
    int d = o -> cmp(val);
    if(d == -1)return true;
    o = o -> son[d];
  }
  return false;
}
void merge_tree(Node * & o,Node * & root)///have modify in this point
{
    if(o -> son[0] != NULL)merge_tree(o -> son[0],root);
    if(o -> son[1] != NULL)merge_tree(o -> son[1],root);
    insert(root,o -> value);
    delete o;
    o = NULL;  /// point o is deleted will point to random
}
void delete_tree(Node * & o)///have modified in this point
{
    if(o -> son[0] != NULL)delete_tree(o -> son[0]);
    if(o -> son[1] != NULL)delete_tree(o -> son[1]);
    delete o;
    o = NULL; /// make point point to NULL
}
int get_next(int u){
  int ro=findfa(u);
  if(num[ro]==n)return -1;
//  for (int i = 1; i < 10; ++i) {
//    cout << -find_kth(root[ro],i) << " ";
//  }
  //puts("");
  int l = 1,r=n;
  while (l < r){
    int cm = (l+r)/2;
    int k = -find_kth(root[ro],cm);
//    cout << "cm" << cm << endl;
//    cout << "l" << l << endl;
//    cout << "r" << r << endl;
//    cout << "k" << k << endl;
    if(cm==k)l=cm+1;
    else r=cm;
  }
  //cout << u << " u v " << l << endl;
  if(!find(root[ro],-l)){
    insert(root[ro],-l);
    num[ro]++;
  }
  ans--;
  fa[l] = ro;
  return l;
}
void dfs(int u){
  for (auto v:vec[u]) {
    int ro=findfa(u);
    if(!find(root[ro],-v) && se.find(v)==se.end()){
      insert(root[ro],-v);
      num[ro]++;
    }
  }
  se.insert(u);
  vector<int>nxt;
  while(1){
    int v = get_next(u);
    if(v == -1)break;
    nxt.push_back(v);
    se.insert(v);
  }
  for (auto v:vec[u]) {
    int ro=findfa(u);
    if(se.find(v)==se.end() && find(root[ro],-v)){
      remove(root[ro],-v);
      num[ro]--;
    }
  }
  for (auto v:nxt) {
    dfs(v);
  }

}
int main()
{
//  root[0]=new Node(1);
//  insert(root[0],2);
//  insert(root[0],4);
//  insert(root[0],5);
//  cout << find_kth(root[0],1) << endl;
//  cout << find_kth(root[0],2) << endl;
//  cout << find_kth(root[0],3) << endl;
//  cout << find_kth(root[0],4) << endl;
//  cout << find_kth(root[0],5) << endl;

  cin >> n >> m;
  ans=n-1;
  for (int i = 0; i < m; ++i) {
    int u,v;
    scanf("%d%d",&u,&v);
    vec[u].push_back(v);
    vec[v].push_back(u);
  }
  for(int i = 1;i <= n;i++){
    fa[i] = i;
    root[i] = new Node(-i);
    num[i]=1;
  }
  for (int i = 1; i <= n; ++i) {
    if(findfa(i)==i){
      se.clear();
      dfs(i);
    }
  }
  cout << ans << endl;
}


#include<bits/stdc++.h>
using namespace std;
struct Node
{
    int value,rank,kth;
    Node * son[2];
    Node(int value) : value(value) {
        son[0] = son[1] = NULL;
        rank = rand();
        kth = 1;
    }
    bool operator < (const Node & nod)const{
        return rank < nod.rank;
    }
    int cmp(int val){
        if(value == val)return -1;
        return val < value ? 0 : 1;
    }
    void maintain(){
        kth = 1;
        if(son[0] != NULL)kth += son[0] -> kth;
        if(son[1] != NULL)kth += son[1] -> kth;
    }
};
void rotate(Node * & o,int d)
{
    Node * k = o -> son[1 ^ d];
    o -> son[1 ^ d] = k -> son[d];
    k -> son[d] = o;
    o -> maintain();
    k -> maintain();
    o = k;
}
void insert(Node * & o,int val)
{
    if(o == NULL) o = new Node(val);
    else
    {
        int d = val < o -> value ? 0 : 1;
        insert(o -> son[d],val);
        if(o < o -> son[d])rotate(o,d ^ 1);
    }
    o -> maintain();///maintain inserted point's ancestors
}
void remove(Node * & o,int val)
{
  int d = o -> cmp(val);
  if(d == -1)
  {
    Node * u = o;
    if(o -> son[0] != NULL && o -> son[1] != NULL)
    {
      bool d2 = o -> son[0] < o -> son[1];
      rotate(o,d2 ^ 1);
      remove(o -> son[d2 ^ 1],val);
    }
    else
    {
      if(o -> son[0] == NULL)  o = o -> son[1];
      else    o = o -> son[0];
      delete u;
    }
  }
  else
    remove(o -> son[d],val);
  if(o != NULL)o -> maintain(); ///o maybe point to the NULL
}
const int MAXN = 1e5+20;
vector<int>vec[MAXN];
int fa[MAXN],n,m,num[MAXN],ans;
Node * froot;
int se[MAXN];
int findfa(int i)
{
    return fa[i] == i ? fa[i] : fa[i] = findfa(fa[i]);
}
int find_kth(Node * & o,int k)
{
    if(o == NULL || o -> kth < k || k <= 0) return 0;
    int s = (o -> son[1] == NULL) ? 0 : o -> son[1] -> kth;
    if(k - 1 - s == 0)return o -> value;
    else if(k - 1 - s > 0)return find_kth(o -> son[0],k - 1 - s);
    else return find_kth(o -> son[1],k);
}
bool find(Node * o , int val){
  while(o != NULL)
  {
    int d = o -> cmp(val);
    if(d == -1)return true;
    o = o -> son[d];
  }
  return false;
}
void merge_tree(Node * & o,Node * & root)///have modify in this point
{
    if(o -> son[0] != NULL)merge_tree(o -> son[0],root);
    if(o -> son[1] != NULL)merge_tree(o -> son[1],root);
    insert(root,o -> value);
    delete o;
    o = NULL;  /// point o is deleted will point to random
}
void delete_tree(Node * & o)///have modified in this point
{
    if(o -> son[0] != NULL)delete_tree(o -> son[0]);
    if(o -> son[1] != NULL)delete_tree(o -> son[1]);
    delete o;
    o = NULL; /// make point point to NULL
}
int get_next(int u){
  int ro=findfa(u);
//  for (int i = 1; i < 10; ++i) {
//    cout << -find_kth(root[ro],i) << " ";
//  }
  //puts("");
  int l = 1,r=n,cnt=0;
  while (l < r){
    cnt++;
    int cm = (l+r)/2;
    int k = -find_kth(froot,cm);
    if(cm==k)l=cm+1;
    else r=cm;
  }
//  cout << u << " u v " << l << endl;
  if(!find(froot,-l)){
    insert(froot,-l);
  }
  else return -1;
  ans--;
  fa[l] = ro;
  return l;
}
void dfs(int u){
  for (auto v:vec[u]) {
    if(!find(froot,-v) && !se[v]){
      insert(froot,-v);
    }
  }
  se[u]=1;
  vector<int>nxt;
  while(1){
    int v = get_next(u);
    if(v == -1)break;
    nxt.push_back(v);
    se[v]=1;
  }
  for (auto v:vec[u]) {
    if(!se[v] && find(froot,-v)){
      remove(froot,-v);
    }
  }
  for (auto v:nxt) {
    dfs(v);
  }

}
int main()
{
  scanf("%d%d",&n,&m);
  ans=n-1;
  for (int i = 0; i < m; ++i) {
    int u,v;
    scanf("%d%d",&u,&v);
    vec[u].push_back(v);
    vec[v].push_back(u);
  }
  for(int i = 1;i <= n;i++){
    fa[i] = i;
  }
  for (int i = 1; i <= n; ++i) {
    if(findfa(i)==i){
      insert(froot,-i);
      dfs(i);
    }
  }
  printf("%d\n",ans);
}


#include<bits/stdc++.h>
using namespace std;
struct Node
{
    int value,rank,kth;
    Node * son[2];
    Node(int value) : value(value) {
        son[0] = son[1] = NULL;
        rank = rand();
        kth = 1;
    }
    bool operator < (const Node & nod)const{
        return rank < nod.rank;
    }
    int cmp(int val){
        if(value == val)return -1;
        return val < value ? 0 : 1;
    }
    void maintain(){
        kth = 1;
        if(son[0] != NULL)kth += son[0] -> kth;
        if(son[1] != NULL)kth += son[1] -> kth;
    }
};
void rotate(Node * & o,int d)
{
    Node * k = o -> son[1 ^ d];
    o -> son[1 ^ d] = k -> son[d];
    k -> son[d] = o;
    o -> maintain();
    k -> maintain();
    o = k;
}
void insert(Node * & o,int val)
{
    if(o == NULL) o = new Node(val);
    else
    {
        int d = val < o -> value ? 0 : 1;
        insert(o -> son[d],val);
        if(o < o -> son[d])rotate(o,d ^ 1);
    }
    o -> maintain();///maintain inserted point's ancestors
}
void remove(Node * & o,int val)
{
  int d = o -> cmp(val);
  if(d == -1)
  {
    Node * u = o;
    if(o -> son[0] != NULL && o -> son[1] != NULL)
    {
      bool d2 = o -> son[0] < o -> son[1];
      rotate(o,d2 ^ 1);
      remove(o -> son[d2 ^ 1],val);
    }
    else
    {
      if(o -> son[0] == NULL)  o = o -> son[1];
      else    o = o -> son[0];
      delete u;
    }
  }
  else
    remove(o -> son[d],val);
  if(o != NULL)o -> maintain(); ///o maybe point to the NULL
}
const int MAXN = 1e5+20;
vector<int>vec[MAXN];
int fa[MAXN],n,m,num[MAXN],ans;
Node * root[MAXN];
set<int>se;
int findfa(int i)
{
    return fa[i] == i ? fa[i] : fa[i] = findfa(fa[i]);
}
int find_kth(Node * & o,int k)
{
    if(o == NULL || o -> kth < k || k <= 0) return 0;
    int s = (o -> son[1] == NULL) ? 0 : o -> son[1] -> kth;
    if(k - 1 - s == 0)return o -> value;
    else if(k - 1 - s > 0)return find_kth(o -> son[0],k - 1 - s);
    else return find_kth(o -> son[1],k);
}
bool find(Node * o , int val){
  while(o != NULL)
  {
    int d = o -> cmp(val);
    if(d == -1)return true;
    o = o -> son[d];
  }
  return false;
}
void merge_tree(Node * & o,Node * & root)///have modify in this point
{
    if(o -> son[0] != NULL)merge_tree(o -> son[0],root);
    if(o -> son[1] != NULL)merge_tree(o -> son[1],root);
    insert(root,o -> value);
    delete o;
    o = NULL;  /// point o is deleted will point to random
}
void delete_tree(Node * & o)///have modified in this point
{
    if(o -> son[0] != NULL)delete_tree(o -> son[0]);
    if(o -> son[1] != NULL)delete_tree(o -> son[1]);
    delete o;
    o = NULL; /// make point point to NULL
}
int get_next(int u){
  int ro=findfa(u);
  if(num[ro]==n)return -1;
//  for (int i = 1; i < 10; ++i) {
//    cout << -find_kth(root[ro],i) << " ";
//  }
  //puts("");
  int l = 1,r=n;
  while (l < r){
    int cm = (l+r)/2;
    int k = -find_kth(root[ro],cm);
//    cout << "cm" << cm << endl;
//    cout << "l" << l << endl;
//    cout << "r" << r << endl;
//    cout << "k" << k << endl;
    if(cm==k)l=cm+1;
    else r=cm;
  }
  //cout << u << " u v " << l << endl;
  if(!find(root[ro],-l)){
    insert(root[ro],-l);
    num[ro]++;
  }
  ans--;
  fa[l] = ro;
  return l;
}
void dfs(int u){
  for (auto v:vec[u]) {
    int ro=findfa(u);
    if(!find(root[ro],-v) && se.find(v)==se.end()){
      insert(root[ro],-v);
      num[ro]++;
    }
  }
  se.insert(u);
  vector<int>nxt;
  while(1){
    int v = get_next(u);
    if(v == -1)break;
    nxt.push_back(v);
    se.insert(v);
  }
  for (auto v:vec[u]) {
    int ro=findfa(u);
    if(se.find(v)==se.end() && find(root[ro],-v)){
      remove(root[ro],-v);
      num[ro]--;
    }
  }
  for (auto v:nxt) {
    dfs(v);
  }

}
int main()
{
//  root[0]=new Node(1);
//  insert(root[0],2);
//  insert(root[0],4);
//  insert(root[0],5);
//  cout << find_kth(root[0],1) << endl;
//  cout << find_kth(root[0],2) << endl;
//  cout << find_kth(root[0],3) << endl;
//  cout << find_kth(root[0],4) << endl;
//  cout << find_kth(root[0],5) << endl;

  scanf("%d%d",&n,&m);
  ans=n-1;
  for (int i = 0; i < m; ++i) {
    int u,v;
    scanf("%d%d",&u,&v);
    vec[u].push_back(v);
    vec[v].push_back(u);
  }
  for(int i = 1;i <= n;i++){
    fa[i] = i;
    root[i] = new Node(-i);
    num[i]=1;
  }
  for (int i = 1; i <= n; ++i) {
    if(findfa(i)==i){
      se.clear();
      dfs(i);
    }
  }
  printf("%d\n",ans);
}


#include<bits/stdc++.h>
using namespace std;
struct Node
{
    int value,rank,kth;
    Node * son[2];
    Node(int value) : value(value) {
        son[0] = son[1] = NULL;
        rank = rand();
        kth = 1;
    }
    bool operator < (const Node & nod)const{
        return rank < nod.rank;
    }
    int cmp(int val){
        if(value == val)return -1;
        return val < value ? 0 : 1;
    }
    void maintain(){
        kth = 1;
        if(son[0] != NULL)kth += son[0] -> kth;
        if(son[1] != NULL)kth += son[1] -> kth;
    }
};
void rotate(Node * & o,int d)
{
    Node * k = o -> son[1 ^ d];
    o -> son[1 ^ d] = k -> son[d];
    k -> son[d] = o;
    o -> maintain();
    k -> maintain();
    o = k;
}
void insert(Node * & o,int val)
{
    if(o == NULL) o = new Node(val);
    else
    {
        int d = val < o -> value ? 0 : 1;
        insert(o -> son[d],val);
        if(o < o -> son[d])rotate(o,d ^ 1);
    }
    o -> maintain();///maintain inserted point's ancestors
}
void remove(Node * & o,int val)
{
  int d = o -> cmp(val);
  if(d == -1)
  {
    Node * u = o;
    if(o -> son[0] != NULL && o -> son[1] != NULL)
    {
      bool d2 = o -> son[0] < o -> son[1];
      rotate(o,d2 ^ 1);
      remove(o -> son[d2 ^ 1],val);
    }
    else
    {
      if(o -> son[0] == NULL)  o = o -> son[1];
      else    o = o -> son[0];
      delete u;
    }
  }
  else
    remove(o -> son[d],val);
  if(o != NULL)o -> maintain(); ///o maybe point to the NULL
}
const int MAXN = 1e5+20;
vector<int>vec[MAXN];
int fa[MAXN],n,m,num[MAXN],ans;
Node * root[MAXN];
set<int>se;
int findfa(int i)
{
    return fa[i] == i ? fa[i] : fa[i] = findfa(fa[i]);
}
int find_kth(Node * & o,int k)
{
    if(o == NULL || o -> kth < k || k <= 0) return 0;
    int s = (o -> son[1] == NULL) ? 0 : o -> son[1] -> kth;
    if(k - 1 - s == 0)return o -> value;
    else if(k - 1 - s > 0)return find_kth(o -> son[0],k - 1 - s);
    else return find_kth(o -> son[1],k);
}
bool find(Node * o , int val){
  while(o != NULL)
  {
    int d = o -> cmp(val);
    if(d == -1)return true;
    o = o -> son[d];
  }
  return false;
}
void merge_tree(Node * & o,Node * & root)///have modify in this point
{
    if(o -> son[0] != NULL)merge_tree(o -> son[0],root);
    if(o -> son[1] != NULL)merge_tree(o -> son[1],root);
    insert(root,o -> value);
    delete o;
    o = NULL;  /// point o is deleted will point to random
}
void delete_tree(Node * & o)///have modified in this point
{
    if(o -> son[0] != NULL)delete_tree(o -> son[0]);
    if(o -> son[1] != NULL)delete_tree(o -> son[1]);
    delete o;
    o = NULL; /// make point point to NULL
}
int get_next(int u){
  int ro=findfa(u);
  if(num[ro]==n)return -1;
//  for (int i = 1; i < 10; ++i) {
//    cout << -find_kth(root[ro],i) << " ";
//  }
  //puts("");
  int l = 1,r=n;
  while (l < r){
    int cm = (l+r)/2;
    int k = -find_kth(root[ro],cm);
//    cout << "cm" << cm << endl;
//    cout << "l" << l << endl;
//    cout << "r" << r << endl;
//    cout << "k" << k << endl;
    if(cm==k)l=cm+1;
    else r=cm;
  }
  //cout << u << " u v " << l << endl;
  if(!find(root[ro],-l)){
    insert(root[ro],-l);
    num[ro]++;
  }
  ans--;
  fa[l] = ro;
  return l;
}
void dfs(int u){
  for (auto v:vec[u]) {
    int ro=findfa(u);
    if(!find(root[ro],-v)){
      insert(root[ro],-v);
      num[ro]++;
    }
  }
  se.insert(u);
  vector<int>nxt;
  while(1){
    int v = get_next(u);
    if(v == -1)break;
    nxt.push_back(v);
    se.insert(v);
  }
  for (auto v:vec[u]) {
    int ro=findfa(u);
    if(se.find(v)==se.end() && !find(root[ro],-v)){
      remove(root[ro],-v);
      num[ro]--;
    }
  }
  for (auto v:nxt) {
    dfs(v);
  }

}
int main()
{
//  root[0]=new Node(1);
//  insert(root[0],2);
//  insert(root[0],4);
//  insert(root[0],5);
//  cout << find_kth(root[0],1) << endl;
//  cout << find_kth(root[0],2) << endl;
//  cout << find_kth(root[0],3) << endl;
//  cout << find_kth(root[0],4) << endl;
//  cout << find_kth(root[0],5) << endl;

  cin >> n >> m;
  ans=n-1;
  for (int i = 0; i < m; ++i) {
    int u,v;
    scanf("%d%d",&u,&v);
    vec[u].push_back(v);
    vec[v].push_back(u);
  }
  for(int i = 1;i <= n;i++){
    fa[i] = i;
    root[i] = new Node(-i);
    num[i]=1;
  }
  for (int i = 1; i <= n; ++i) {
    if(findfa(i)==i){
      se.clear();
      dfs(i);
    }
  }
  cout << ans << endl;
}


#include<bits/stdc++.h>
using namespace std;
struct Node
{
    int value,rank,kth;
    Node * son[2];
    Node(int value) : value(value) {
        son[0] = son[1] = NULL;
        rank = rand();
        kth = 1;
    }
    bool operator < (const Node & nod)const{
        return rank < nod.rank;
    }
    int cmp(int val){
        if(value == val)return -1;
        return val < value ? 0 : 1;
    }
    void maintain(){
        kth = 1;
        if(son[0] != NULL)kth += son[0] -> kth;
        if(son[1] != NULL)kth += son[1] -> kth;
    }
};
void rotate(Node * & o,int d)
{
    Node * k = o -> son[1 ^ d];
    o -> son[1 ^ d] = k -> son[d];
    k -> son[d] = o;
    o -> maintain();
    k -> maintain();
    o = k;
}
void insert(Node * & o,int val)
{
    if(o == NULL) o = new Node(val);
    else
    {
        int d = val < o -> value ? 0 : 1;
        insert(o -> son[d],val);
        if(o < o -> son[d])rotate(o,d ^ 1);
    }
    o -> maintain();///maintain inserted point's ancestors
}
void remove(Node * & o,int val)
{
  int d = o -> cmp(val);
  if(d == -1)
  {
    Node * u = o;
    if(o -> son[0] != NULL && o -> son[1] != NULL)
    {
      bool d2 = o -> son[0] < o -> son[1];
      rotate(o,d2 ^ 1);
      remove(o -> son[d2 ^ 1],val);
    }
    else
    {
      if(o -> son[0] == NULL)  o = o -> son[1];
      else    o = o -> son[0];
      delete u;
    }
  }
  else
    remove(o -> son[d],val);
  if(o != NULL)o -> maintain(); ///o maybe point to the NULL
}
const int MAXN = 1e5+20;
vector<int>vec[MAXN];
int fa[MAXN],n,m,num[MAXN],ans;
Node * root[MAXN];
set<int>se;
int findfa(int i)
{
    return fa[i] == i ? fa[i] : fa[i] = findfa(fa[i]);
}
int find_kth(Node * & o,int k)
{
    if(o == NULL || o -> kth < k || k <= 0) return 0;
    int s = (o -> son[1] == NULL) ? 0 : o -> son[1] -> kth;
    if(k - 1 - s == 0)return o -> value;
    else if(k - 1 - s > 0)return find_kth(o -> son[0],k - 1 - s);
    else return find_kth(o -> son[1],k);
}
bool find(Node * o , int val){
  while(o != NULL)
  {
    int d = o -> cmp(val);
    if(d == -1)return true;
    o = o -> son[d];
  }
  return false;
}
void merge_tree(Node * & o,Node * & root)///have modify in this point
{
    if(o -> son[0] != NULL)merge_tree(o -> son[0],root);
    if(o -> son[1] != NULL)merge_tree(o -> son[1],root);
    insert(root,o -> value);
    delete o;
    o = NULL;  /// point o is deleted will point to random
}
void delete_tree(Node * & o)///have modified in this point
{
    if(o -> son[0] != NULL)delete_tree(o -> son[0]);
    if(o -> son[1] != NULL)delete_tree(o -> son[1]);
    delete o;
    o = NULL; /// make point point to NULL
}
int get_next(int u){
  int ro=findfa(u);
  if(num[ro]==n)return -1;
//  for (int i = 1; i < 10; ++i) {
//    cout << -find_kth(root[ro],i) << " ";
//  }
  //puts("");
  int l = 1,r=n,cnt=0;
  while (l < r){
    cnt++;
    if(cnt > 100)puts("wrong");
    int cm = (l+r)/2;
    int k = -find_kth(root[ro],cm);
//    cout << "cm" << cm << endl;
//    cout << "l" << l << endl;
//    cout << "r" << r << endl;
//    cout << "k" << k << endl;
    if(cm==k)l=cm+1;
    else r=cm;
  }
  //cout << u << " u v " << l << endl;
  if(!find(root[ro],-l)){
    insert(root[ro],-l);
    num[ro]++;
  }
  ans--;
  fa[l] = ro;
  return l;
}
void dfs(int u){
  for (auto v:vec[u]) {
    int ro=findfa(u);
    if(!find(root[ro],-v) && se.find(v)==se.end()){
      insert(root[ro],-v);
      num[ro]++;
    }
  }
  se.insert(u);
  vector<int>nxt;
  while(1){
    int v = get_next(u);
    if(v == -1)break;
    nxt.push_back(v);
  }
  for (auto v:vec[u]) {
    int ro=findfa(u);
    if(se.find(v)==se.end() && find(root[ro],-v)){
      remove(root[ro],-v);
      num[ro]--;
    }
  }
  for (auto v:nxt) {
    dfs(v);
  }

}
int main()
{
//  root[0]=new Node(1);
//  insert(root[0],2);
//  insert(root[0],4);
//  insert(root[0],5);
//  cout << find_kth(root[0],1) << endl;
//  cout << find_kth(root[0],2) << endl;
//  cout << find_kth(root[0],3) << endl;
//  cout << find_kth(root[0],4) << endl;
//  cout << find_kth(root[0],5) << endl;

  scanf("%d%d",&n,&m);
  ans=n-1;
  for (int i = 0; i < m; ++i) {
    int u,v;
    scanf("%d%d",&u,&v);
    vec[u].push_back(v);
    vec[v].push_back(u);
  }
  for(int i = 1;i <= n;i++){
    fa[i] = i;
    root[i] = new Node(-i);
    num[i]=1;
  }
  for (int i = 1; i <= n; ++i) {
    if(findfa(i)==i){
      se.clear();
      dfs(i);
    }
  }
  printf("%d\n",ans);
}


#include<bits/stdc++.h>
using namespace std;
struct Node
{
    int value,rank,kth;
    Node * son[2];
    Node(int value) : value(value) {
        son[0] = son[1] = NULL;
        rank = rand();
        kth = 1;
    }
    bool operator < (const Node & nod)const{
        return rank < nod.rank;
    }
    int cmp(int val){
        if(value == val)return -1;
        return val < value ? 0 : 1;
    }
    void maintain(){
        kth = 1;
        if(son[0] != NULL)kth += son[0] -> kth;
        if(son[1] != NULL)kth += son[1] -> kth;
    }
};
void rotate(Node * & o,int d)
{
    Node * k = o -> son[1 ^ d];
    o -> son[1 ^ d] = k -> son[d];
    k -> son[d] = o;
    o -> maintain();
    k -> maintain();
    o = k;
}
void insert(Node * & o,int val)
{
    if(o == NULL) o = new Node(val);
    else
    {
        int d = val < o -> value ? 0 : 1;
        insert(o -> son[d],val);
        if(o < o -> son[d])rotate(o,d ^ 1);
    }
    o -> maintain();///maintain inserted point's ancestors
}
void remove(Node * & o,int val)
{
  int d = o -> cmp(val);
  if(d == -1)
  {
    Node * u = o;
    if(o -> son[0] != NULL && o -> son[1] != NULL)
    {
      bool d2 = o -> son[0] < o -> son[1];
      rotate(o,d2 ^ 1);
      remove(o -> son[d2 ^ 1],val);
    }
    else
    {
      if(o -> son[0] == NULL)  o = o -> son[1];
      else    o = o -> son[0];
      delete u;
    }
  }
  else
    remove(o -> son[d],val);
  if(o != NULL)o -> maintain(); ///o maybe point to the NULL
}
const int MAXN = 1e5+20;
vector<int>vec[MAXN];
int fa[MAXN],n,m,num[MAXN],ans;
Node * root[MAXN];
set<int>se;
int findfa(int i)
{
    return fa[i] == i ? fa[i] : fa[i] = findfa(fa[i]);
}
int find_kth(Node * & o,int k)
{
    if(o == NULL || o -> kth < k || k <= 0) return 0;
    int s = (o -> son[1] == NULL) ? 0 : o -> son[1] -> kth;
    if(k - 1 - s == 0)return o -> value;
    else if(k - 1 - s > 0)return find_kth(o -> son[0],k - 1 - s);
    else return find_kth(o -> son[1],k);
}
bool find(Node * o , int val){
  while(o != NULL)
  {
    int d = o -> cmp(val);
    if(d == -1)return true;
    o = o -> son[d];
  }
  return false;
}
void merge_tree(Node * & o,Node * & root)///have modify in this point
{
    if(o -> son[0] != NULL)merge_tree(o -> son[0],root);
    if(o -> son[1] != NULL)merge_tree(o -> son[1],root);
    insert(root,o -> value);
    delete o;
    o = NULL;  /// point o is deleted will point to random
}
void delete_tree(Node * & o)///have modified in this point
{
    if(o -> son[0] != NULL)delete_tree(o -> son[0]);
    if(o -> son[1] != NULL)delete_tree(o -> son[1]);
    delete o;
    o = NULL; /// make point point to NULL
}
int get_next(int u){
  int ro=findfa(u);
  if(num[ro]==n)return -1;
//  for (int i = 1; i < 10; ++i) {
//    cout << -find_kth(root[ro],i) << " ";
//  }
  //puts("");
  int l = 1,r=n,cnt=0;
  while (l < r){
    cnt++;
    if(cnt > 100)puts("wrong");
    int cm = (l+r)/2;
    int k = -find_kth(root[ro],cm);
//    cout << "cm" << cm << endl;
//    cout << "l" << l << endl;
//    cout << "r" << r << endl;
//    cout << "k" << k << endl;
    if(cm==k)l=cm+1;
    else r=cm;
  }
  //cout << u << " u v " << l << endl;
  if(!find(root[ro],-l)){
    insert(root[ro],-l);
    num[ro]++;
  }
  ans--;
  fa[l] = ro;
  return l;
}
void dfs(int u){
  for (auto v:vec[u]) {
    int ro=findfa(u);
    if(!find(root[ro],-v) && se.find(v)==se.end()){
      insert(root[ro],-v);
      num[ro]++;
    }
  }
  se.insert(u);
  vector<int>nxt;
  while(1){
    int v = get_next(u);
    if(v == -1)break;
    nxt.push_back(v);
    se.insert(v);
  }
  for (auto v:vec[u]) {
    int ro=findfa(u);
    if(se.find(v)==se.end() && find(root[ro],-v)){
      remove(root[ro],-v);
      num[ro]--;
    }
  }
  for (auto v:nxt) {
    dfs(v);
  }

}
int main()
{
//  root[0]=new Node(1);
//  insert(root[0],2);
//  insert(root[0],4);
//  insert(root[0],5);
//  cout << find_kth(root[0],1) << endl;
//  cout << find_kth(root[0],2) << endl;
//  cout << find_kth(root[0],3) << endl;
//  cout << find_kth(root[0],4) << endl;
//  cout << find_kth(root[0],5) << endl;

  scanf("%d%d",&n,&m);
  ans=n-1;
  for (int i = 0; i < m; ++i) {
    int u,v;
    scanf("%d%d",&u,&v);
    vec[u].push_back(v);
    vec[v].push_back(u);
  }
  for(int i = 1;i <= n;i++){
    fa[i] = i;
    root[i] = new Node(-i);
    num[i]=1;
  }
  for (int i = 1; i <= n; ++i) {
    if(findfa(i)==i){
      se.clear();
      dfs(i);
    }
  }
  printf("%d\n",ans);
}


#include<bits/stdc++.h>
using namespace std;
struct Node
{
    int value,rank,kth;
    Node * son[2];
    Node(int value) : value(value) {
        son[0] = son[1] = NULL;
        rank = rand();
        kth = 1;
    }
    bool operator < (const Node & nod)const{
        return rank < nod.rank;
    }
    int cmp(int val){
        if(value == val)return -1;
        return val < value ? 0 : 1;
    }
    void maintain(){
        kth = 1;
        if(son[0] != NULL)kth += son[0] -> kth;
        if(son[1] != NULL)kth += son[1] -> kth;
    }
};
void rotate(Node * & o,int d)
{
    Node * k = o -> son[1 ^ d];
    o -> son[1 ^ d] = k -> son[d];
    k -> son[d] = o;
    o -> maintain();
    k -> maintain();
    o = k;
}
void insert(Node * & o,int val)
{
    if(o == NULL) o = new Node(val);
    else
    {
        int d = val < o -> value ? 0 : 1;
        insert(o -> son[d],val);
        if(o < o -> son[d])rotate(o,d ^ 1);
    }
    o -> maintain();///maintain inserted point's ancestors
}
void remove(Node * & o,int val)
{
  int d = o -> cmp(val);
  if(d == -1)
  {
    Node * u = o;
    if(o -> son[0] != NULL && o -> son[1] != NULL)
    {
      bool d2 = o -> son[0] < o -> son[1];
      rotate(o,d2 ^ 1);
      remove(o -> son[d2 ^ 1],val);
    }
    else
    {
      if(o -> son[0] == NULL)  o = o -> son[1];
      else    o = o -> son[0];
      delete u;
    }
  }
  else
    remove(o -> son[d],val);
  if(o != NULL)o -> maintain(); ///o maybe point to the NULL
}
const int MAXN = 1e5+20;
vector<int>vec[MAXN];
int fa[MAXN],n,m,num[MAXN],ans;
Node * froot;
set<int>se;
int findfa(int i)
{
    return fa[i] == i ? fa[i] : fa[i] = findfa(fa[i]);
}
int find_kth(Node * & o,int k)
{
    if(o == NULL || o -> kth < k || k <= 0) return 0;
    int s = (o -> son[1] == NULL) ? 0 : o -> son[1] -> kth;
    if(k - 1 - s == 0)return o -> value;
    else if(k - 1 - s > 0)return find_kth(o -> son[0],k - 1 - s);
    else return find_kth(o -> son[1],k);
}
bool find(Node * o , int val){
  while(o != NULL)
  {
    int d = o -> cmp(val);
    if(d == -1)return true;
    o = o -> son[d];
  }
  return false;
}
void merge_tree(Node * & o,Node * & root)///have modify in this point
{
    if(o -> son[0] != NULL)merge_tree(o -> son[0],root);
    if(o -> son[1] != NULL)merge_tree(o -> son[1],root);
    insert(root,o -> value);
    delete o;
    o = NULL;  /// point o is deleted will point to random
}
void delete_tree(Node * & o)///have modified in this point
{
    if(o -> son[0] != NULL)delete_tree(o -> son[0]);
    if(o -> son[1] != NULL)delete_tree(o -> son[1]);
    delete o;
    o = NULL; /// make point point to NULL
}
int get_next(int u){
  int ro=findfa(u);
//  if(num[ro]==n)return -1;
//  for (int i = 1; i < 10; ++i) {
//    cout << -find_kth(root[ro],i) << " ";
//  }
  //puts("");
  int l = 1,r=n,cnt=0;
  while (l < r){
    cnt++;
    if(cnt > 100)puts("wrong");
    int cm = (l+r)/2;
    int k = -find_kth(froot,cm);
//    cout << "cm" << cm << endl;
//    cout << "l" << l << endl;
//    cout << "r" << r << endl;
//    cout << "k" << k << endl;
    if(cm==k)l=cm+1;
    else r=cm;
  }
//  cout << u << " u v " << l << endl;
  if(!find(froot,-l)){
    insert(froot,-l);
//    num[ro]++;
  }
  else return -1;
  ans--;
  fa[l] = ro;
  return l;
}
void dfs(int u){
  for (auto v:vec[u]) {
    int ro=findfa(u);
    if(!find(froot,-v) && se.find(v)==se.end()){
      insert(froot,-v);
//      num[ro]++;
    }
  }
  se.insert(u);
  vector<int>nxt;
  while(1){
    int v = get_next(u);
    if(v == -1)break;
    nxt.push_back(v);
  }
  for (auto v:vec[u]) {
    int ro=findfa(u);
    if(se.find(v)==se.end() && find(froot,-v)){
      remove(froot,-v);
//      num[ro]--;
    }
  }
  for (auto v:nxt) {
    dfs(v);
  }

}
int main()
{
//  root[0]=new Node(1);
//  insert(root[0],2);
//  insert(root[0],4);
//  insert(root[0],5);
//  cout << find_kth(root[0],1) << endl;
//  cout << find_kth(root[0],2) << endl;
//  cout << find_kth(root[0],3) << endl;
//  cout << find_kth(root[0],4) << endl;
//  cout << find_kth(root[0],5) << endl;

  scanf("%d%d",&n,&m);
  ans=n-1;
  for (int i = 0; i < m; ++i) {
    int u,v;
    scanf("%d%d",&u,&v);
    vec[u].push_back(v);
    vec[v].push_back(u);
  }
  for(int i = 1;i <= n;i++){
    fa[i] = i;
//    num[i]=1;
  }
  for (int i = 1; i <= n; ++i) {
    if(findfa(i)==i){
      insert(froot,-i);
      se.clear();
      dfs(i);
    }
  }
  printf("%d\n",ans);
}


#include<bits/stdc++.h>
using namespace std;
struct Node
{
    int value,rank,kth;
    Node * son[2];
    Node(int value) : value(value) {
        son[0] = son[1] = NULL;
        rank = rand();
        kth = 1;
    }
    bool operator < (const Node & nod)const{
        return rank < nod.rank;
    }
    int cmp(int val){
        if(value == val)return -1;
        return val < value ? 0 : 1;
    }
    void maintain(){
        kth = 1;
        if(son[0] != NULL)kth += son[0] -> kth;
        if(son[1] != NULL)kth += son[1] -> kth;
    }
};
void rotate(Node * & o,int d)
{
    Node * k = o -> son[1 ^ d];
    o -> son[1 ^ d] = k -> son[d];
    k -> son[d] = o;
    o -> maintain();
    k -> maintain();
    o = k;
}
void insert(Node * & o,int val)
{
    if(o == NULL) o = new Node(val);
    else
    {
        int d = val < o -> value ? 0 : 1;
        insert(o -> son[d],val);
        if(o < o -> son[d])rotate(o,d ^ 1);
    }
    o -> maintain();///maintain inserted point's ancestors
}
void remove(Node * & o,int val)
{
  int d = o -> cmp(val);
  if(d == -1)
  {
    Node * u = o;
    if(o -> son[0] != NULL && o -> son[1] != NULL)
    {
      bool d2 = o -> son[0] < o -> son[1];
      rotate(o,d2 ^ 1);
      remove(o -> son[d2 ^ 1],val);
    }
    else
    {
      if(o -> son[0] == NULL)  o = o -> son[1];
      else    o = o -> son[0];
      delete u;
    }
  }
  else
    remove(o -> son[d],val);
  if(o != NULL)o -> maintain(); ///o maybe point to the NULL
}
const int MAXN = 1e5+20;
vector<int>vec[MAXN];
int fa[MAXN],n,m,num[MAXN],ans;
Node * root[MAXN];
int findfa(int i)
{
    return fa[i] == i ? fa[i] : fa[i] = findfa(fa[i]);
}
int find_kth(Node * & o,int k)
{
    if(o == NULL || o -> kth < k || k <= 0) return 0;
    int s = (o -> son[1] == NULL) ? 0 : o -> son[1] -> kth;
    if(k - 1 - s == 0)return o -> value;
    else if(k - 1 - s > 0)return find_kth(o -> son[0],k - 1 - s);
    else return find_kth(o -> son[1],k);
}
bool find(Node * o , int val){
  while(o != NULL)
  {
    int d = o -> cmp(val);
    if(d == -1)return true;
    o = o -> son[d];
  }
  return false;
}
void merge_tree(Node * & o,Node * & root)///have modify in this point
{
    if(o -> son[0] != NULL)merge_tree(o -> son[0],root);
    if(o -> son[1] != NULL)merge_tree(o -> son[1],root);
    insert(root,o -> value);
    delete o;
    o = NULL;  /// point o is deleted will point to random
}
void delete_tree(Node * & o)///have modified in this point
{
    if(o -> son[0] != NULL)delete_tree(o -> son[0]);
    if(o -> son[1] != NULL)delete_tree(o -> son[1]);
    delete o;
    o = NULL; /// make point point to NULL
}
int get_next(int u){
  int ro=findfa(u);
  if(num[ro]==n)return -1;
//  for (int i = 1; i < 10; ++i) {
//    cout << -find_kth(root[ro],i) << " ";
//  }
  //puts("");
  int l = 1,r=n;
  while (l < r){
    int m = (l+r)/2;
    int k = -find_kth(root[ro],m);
//    cout << "m" << m << endl;
//    cout << "l" << l << endl;
//    cout << "r" << r << endl;
//    cout << "k" << k << endl;
    if(m==k)l=m+1;
    else r=m;
  }
  //cout << u << " u v " << l << endl;
  if(!find(root[ro],-l)){
    insert(root[ro],-l);
    num[ro]++;
  }
  ans--;
  for (auto v:vec[l]) {
    if(find(root[ro],-v))continue;
    insert(root[ro],-v);
    num[ro]++;
  }
  fa[l] = ro;
  return l;
}
void dfs(int u){
  while(1){
    int v = get_next(u);
    if(v == -1)break;
    dfs(v);
  }
}
int main()
{
//  root[0]=new Node(1);
//  insert(root[0],2);
//  insert(root[0],4);
//  insert(root[0],5);
//  cout << find_kth(root[0],1) << endl;
//  cout << find_kth(root[0],2) << endl;
//  cout << find_kth(root[0],3) << endl;
//  cout << find_kth(root[0],4) << endl;
//  cout << find_kth(root[0],5) << endl;

  cin >> n >> m;
  ans=n-1;
  for (int i = 0; i < m; ++i) {
    int u,v;
    scanf("%d%d",&u,&v);
    vec[u].push_back(v);
    vec[v].push_back(u);
  }
  for(int i = 1;i <= n;i++){
    fa[i] = i;
    root[i] = new Node(-i);
    num[i]=1;
  }
  for (int i = 1; i <= n; ++i) {
    for (auto v:vec[i]) {
      if(find(root[i],-v))continue;
      insert(root[i],-v);
      num[i]++;
    }
    if(findfa(i)==i)dfs(i);
  }
  cout << ans << endl;
}


#include<bits/stdc++.h>
using namespace std;
struct Node
{
    int value,rank,kth;
    Node * son[2];
    Node(int value) : value(value) {
        son[0] = son[1] = NULL;
        rank = rand();
        kth = 1;
    }
    bool operator < (const Node & nod)const{
        return rank < nod.rank;
    }
    int cmp(int val){
        if(value == val)return -1;
        return val < value ? 0 : 1;
    }
    void maintain(){
        kth = 1;
        if(son[0] != NULL)kth += son[0] -> kth;
        if(son[1] != NULL)kth += son[1] -> kth;
    }
};
void rotate(Node * & o,int d)
{
    Node * k = o -> son[1 ^ d];
    o -> son[1 ^ d] = k -> son[d];
    k -> son[d] = o;
    o -> maintain();
    k -> maintain();
    o = k;
}
void insert(Node * & o,int val)
{
    if(o == NULL) o = new Node(val);
    else
    {
        int d = val < o -> value ? 0 : 1;
        insert(o -> son[d],val);
        if(o < o -> son[d])rotate(o,d ^ 1);
    }
    o -> maintain();///maintain inserted point's ancestors
}
void remove(Node * & o,int val)
{
  int d = o -> cmp(val);
  if(d == -1)
  {
    Node * u = o;
    if(o -> son[0] != NULL && o -> son[1] != NULL)
    {
      bool d2 = o -> son[0] < o -> son[1];
      rotate(o,d2 ^ 1);
      remove(o -> son[d2 ^ 1],val);
    }
    else
    {
      if(o -> son[0] == NULL)  o = o -> son[1];
      else    o = o -> son[0];
      delete u;
    }
  }
  else
    remove(o -> son[d],val);
  if(o != NULL)o -> maintain(); ///o maybe point to the NULL
}
const int MAXN = 1e5+20;
vector<int>vec[MAXN];
int fa[MAXN],n,m,num[MAXN],ans;
Node * froot;
set<int>se;
int findfa(int i)
{
    return fa[i] == i ? fa[i] : fa[i] = findfa(fa[i]);
}
int find_kth(Node * & o,int k)
{
    if(o == NULL || o -> kth < k || k <= 0) return 0;
    int s = (o -> son[1] == NULL) ? 0 : o -> son[1] -> kth;
    if(k - 1 - s == 0)return o -> value;
    else if(k - 1 - s > 0)return find_kth(o -> son[0],k - 1 - s);
    else return find_kth(o -> son[1],k);
}
bool find(Node * o , int val){
  while(o != NULL)
  {
    int d = o -> cmp(val);
    if(d == -1)return true;
    o = o -> son[d];
  }
  return false;
}
void merge_tree(Node * & o,Node * & root)///have modify in this point
{
    if(o -> son[0] != NULL)merge_tree(o -> son[0],root);
    if(o -> son[1] != NULL)merge_tree(o -> son[1],root);
    insert(root,o -> value);
    delete o;
    o = NULL;  /// point o is deleted will point to random
}
void delete_tree(Node * & o)///have modified in this point
{
    if(o -> son[0] != NULL)delete_tree(o -> son[0]);
    if(o -> son[1] != NULL)delete_tree(o -> son[1]);
    delete o;
    o = NULL; /// make point point to NULL
}
int get_next(int u){
  int ro=findfa(u);
//  for (int i = 1; i < 10; ++i) {
//    cout << -find_kth(root[ro],i) << " ";
//  }
  //puts("");
  int l = 1,r=n,cnt=0;
  while (l < r){
    cnt++;
    int cm = (l+r)/2;
    int k = -find_kth(froot,cm);
    if(cm==k)l=cm+1;
    else r=cm;
  }
//  cout << u << " u v " << l << endl;
  if(!find(froot,-l)){
    insert(froot,-l);
  }
  else return -1;
  ans--;
  fa[l] = ro;
  return l;
}
void dfs(int u){
  for (auto v:vec[u]) {
    if(!find(froot,-v) && se.find(v)==se.end()){
      insert(froot,-v);
    }
  }
  se.insert(u);
  vector<int>nxt;
  while(1){
    int v = get_next(u);
    if(v == -1)break;
    nxt.push_back(v);
    se.insert(v);
  }
  for (auto v:vec[u]) {
    if(se.find(v)==se.end() && find(froot,-v)){
      remove(froot,-v);
    }
  }
  for (auto v:nxt) {
    dfs(v);
  }

}
int main()
{
  scanf("%d%d",&n,&m);
  ans=n-1;
  for (int i = 0; i < m; ++i) {
    int u,v;
    scanf("%d%d",&u,&v);
    vec[u].push_back(v);
    vec[v].push_back(u);
  }
  for(int i = 1;i <= n;i++){
    fa[i] = i;
  }
  for (int i = 1; i <= n; ++i) {
    if(findfa(i)==i){
      insert(froot,-i);
      dfs(i);
    }
  }
  printf("%d\n",ans);
}


#include<bits/stdc++.h>
using namespace std;
struct Node
{
    int value,rank,kth;
    Node * son[2];
    Node(int value) : value(value) {
        son[0] = son[1] = NULL;
        rank = rand();
        kth = 1;
    }
    bool operator < (const Node & nod)const{
        return rank < nod.rank;
    }
    int cmp(int val){
        if(value == val)return -1;
        return val < value ? 0 : 1;
    }
    void maintain(){
        kth = 1;
        if(son[0] != NULL)kth += son[0] -> kth;
        if(son[1] != NULL)kth += son[1] -> kth;
    }
};
void rotate(Node * & o,int d)
{
    Node * k = o -> son[1 ^ d];
    o -> son[1 ^ d] = k -> son[d];
    k -> son[d] = o;
    o -> maintain();
    k -> maintain();
    o = k;
}
void insert(Node * & o,int val)
{
    if(o == NULL) o = new Node(val);
    else
    {
        int d = val < o -> value ? 0 : 1;
        insert(o -> son[d],val);
        if(o < o -> son[d])rotate(o,d ^ 1);
    }
    o -> maintain();///maintain inserted point's ancestors
}
void remove(Node * & o,int val)
{
  int d = o -> cmp(val);
  if(d == -1)
  {
    Node * u = o;
    if(o -> son[0] != NULL && o -> son[1] != NULL)
    {
      bool d2 = o -> son[0] < o -> son[1];
      rotate(o,d2 ^ 1);
      remove(o -> son[d2 ^ 1],val);
    }
    else
    {
      if(o -> son[0] == NULL)  o = o -> son[1];
      else    o = o -> son[0];
      delete u;
    }
  }
  else
    remove(o -> son[d],val);
  if(o != NULL)o -> maintain(); ///o maybe point to the NULL
}
const int MAXN = 1e5+20;
vector<int>vec[MAXN];
int n,m,ans;
Node * froot;
int se[MAXN];
int find_kth(Node * & o,int k)
{
    if(o == NULL || o -> kth < k || k <= 0) return 0;
    int s = (o -> son[1] == NULL) ? 0 : o -> son[1] -> kth;
    if(k - 1 - s == 0)return o -> value;
    else if(k - 1 - s > 0)return find_kth(o -> son[0],k - 1 - s);
    else return find_kth(o -> son[1],k);
}
bool find(Node * o , int val){
  while(o != NULL)
  {
    int d = o -> cmp(val);
    if(d == -1)return true;
    o = o -> son[d];
  }
  return false;
}
void merge_tree(Node * & o,Node * & root)///have modify in this point
{
    if(o -> son[0] != NULL)merge_tree(o -> son[0],root);
    if(o -> son[1] != NULL)merge_tree(o -> son[1],root);
    insert(root,o -> value);
    delete o;
    o = NULL;  /// point o is deleted will point to random
}
void delete_tree(Node * & o)///have modified in this point
{
    if(o -> son[0] != NULL)delete_tree(o -> son[0]);
    if(o -> son[1] != NULL)delete_tree(o -> son[1]);
    delete o;
    o = NULL; /// make point point to NULL
}
int get_next(int u){
//  for (int i = 1; i < 10; ++i) {
//    cout << -find_kth(root[ro],i) << " ";
//  }
  //puts("");
  int l = 1,r=n,cnt=0;
  while (l < r){
    cnt++;
    int cm = (l+r)/2;
    int k = -find_kth(froot,cm);
    if(cm==k)l=cm+1;
    else r=cm;
  }
//  cout << u << " u v " << l << endl;
  if(!find(froot,-l)){
    insert(froot,-l);
  }
  else return -1;
  ans--;
  return l;
}
void dfs(int u){
  for (auto v:vec[u]) {
    if(!find(froot,-v) && !se[v]){
      insert(froot,-v);
    }
  }
  se[u]=1;
  vector<int>nxt;
  while(true){
    int v = get_next(u);
    if(v == -1)break;
    nxt.push_back(v);
    se[v]=1;
  }
  for (auto v:vec[u]) {
    if(!se[v] && find(froot,-v)){
      remove(froot,-v);
    }
  }
  for (auto v:nxt) {
    dfs(v);
  }

}
int main()
{
  scanf("%d%d",&n,&m);
  ans=n-1;
  for (int i = 0; i < m; ++i) {
    int u,v;
    scanf("%d%d",&u,&v);
    vec[u].push_back(v);
    vec[v].push_back(u);
  }
  for (int i = 1; i <= n; ++i) {
    if(!se[i]){
      insert(froot,-i);
      dfs(i);
    }
  }
  printf("%d\n",ans);
}


//Code of C#oder Born_Clear
#include <bits/stdc++.h>
using namespace std;
#define loop(n) for(int i=0;i<n;++i)
#define FORD(i,a,b) for(int i=a;i>=b;--i)
#define pb push_back
#define mp make_pair
#define all(x) x.begin(),x.end()
#define ll long long
#define s(x) scanf("%d", &x)
#define sd(x) scanf("%lf", &x)
#define sl(x) scanf("%lld", &x)
#define mod 1000000007
#define fi first
#define se second
#define p(x) printf("%d",x)
#define pl(x) printf("%lld", x)
#define pd(x) printf("%lf", x)
#define pn() printf("\n")
#define vi(v) vector<int>v
#define vl(v) vector<long long int>v
#define pii pair<int,int>
#define pll pair<long long int,long long int>
#define len(s) s.length()
#define mem1(s) memset(s,-1,sizeof(s))
#define mem(s) memset(s,0,sizeof(s))
void input(int n,int a[]){loop(n)cin>>a[i];}
ll bin_expo(ll A, ll B, ll M){ll res = 1LL;while (B > 0){if(B % 2 == 1){res = (res * A) % M;}A = (A * A) % M; B = B / 2;}return res;}
int pa[1000000];int size[1000000];

vector<int>adj[1000000];
int find_par(int x)
{
	if(pa[x]==x)
		return x;
	return pa[x]=find_par(pa[x]);
}
int main()
{
	int n,m;
	cin>>n>>m;
	for(int i=0;i<m;i++)
	{
		int x,y;
		cin>>x>>y;
		adj[x].pb(y);
		adj[y].pb(x);
	}
	for(int i=1;i<=n;i++)
		if(adj[i].size()!=0)
			sort(all(adj[i]));
	for(int i=0;i<n+2;i++){
		pa[i]=i;
		size[i]=1;
	}

	int ans=0;
	int fre[n+5]={0};
	set<int>cur;
	for(int i=1;i<=n;i++)
	{
		int v=i;
		vector<int>temp;
		cur.insert(v);
		for(int j=0;j<adj[i].size()&&adj[i][j]<=v;j++)
		{
			// if(adj[i][j]>v)
			// 	break;
			int u=adj[i][j];
			int papa=find_par(u);
			fre[papa]++;
			temp.pb(papa);
		}
		for(auto j:cur)
		{
			int p1=find_par(v);
			int p2=find_par(j);
			if(p1!=p2 && fre[p2]!=size[p2])
			{
				if(p1>p2)
					swap(p1,p2);
				pa[p2]=p1;
				size[p1]+=size[p2];
				if(cur.find(p2)!=cur.end())
					cur.erase(p2);
			}
		}
		for(int j=0;j<temp.size();j++)
			fre[temp[j]]=0;
	}
	set<int>s;
	for(int i=1;i<=n;i++)
		s.insert(find_par(i));
	cout<<s.size()-1<<endl;
	return 0;
}


    # include <bits/stdc++.h>
    using namespace std;
    const int N=1e5+10;
    map<int,int>mp[N];
    set<int>s;
    int n,m;
    bool vis[N];
    void dfs(int u) {
    	vis[u]=1; s.erase(u);
    	set<int>::iterator it;
    	vector<int>tmp;
    	for (it=s.begin();it!=s.end();++it) {
    		if (!mp[u].count(*it)) tmp.push_back(*it);
    	}
    	for (int i=0;i<tmp.size();i++) s.erase(tmp[i]);
    	for (int i=0;i<tmp.size();i++) dfs(tmp[i]);
    }
    int main()
    {
    	scanf("%d%d",&n,&m);
    	for (int i=1;i<=m;i++) {
    		int u,v; scanf("%d%d",&u,&v);
    		mp[u][v]=mp[v][u]=1;
    	}
    	for (int i=1;i<=n;i++) s.insert(i);
    	int ans=0;
    	memset(vis,false,sizeof(vis));
    	for (int i=1;i<=n;i++) if (!vis[i]) {
    		ans++; dfs(i);
    	}
    	printf("%d\n",ans-1);
    	return 0;
    }


//Code of C#oder Born_Clear
#include <bits/stdc++.h>
using namespace std;
#define loop(n) for(int i=0;i<n;++i)
#define FORD(i,a,b) for(int i=a;i>=b;--i)
#define pb push_back
#define mp make_pair
#define all(x) x.begin(),x.end()
#define ll long long
#define s(x) scanf("%d", &x)
#define sd(x) scanf("%lf", &x)
#define sl(x) scanf("%lld", &x)
#define mod 1000000007
#define fi first
#define se second
#define p(x) printf("%d",x)
#define pl(x) printf("%lld", x)
#define pd(x) printf("%lf", x)
#define pn() printf("\n")
#define vi(v) vector<int>v
#define vl(v) vector<long long int>v
#define pii pair<int,int>
#define pll pair<long long int,long long int>
#define len(s) s.length()
#define mem1(s) memset(s,-1,sizeof(s))
#define mem(s) memset(s,0,sizeof(s))
void input(int n,int a[]){loop(n)cin>>a[i];}
ll bin_expo(ll A, ll B, ll M){ll res = 1LL;while (B > 0){if(B % 2 == 1){res = (res * A) % M;}A = (A * A) % M; B = B / 2;}return res;}
int pa[1000000];int size[1000000];

vector<int>adj[1000000];
int find_par(int x)
{
	if(pa[x]==x)
		return x;
	return pa[x]=find_par(pa[x]);
}
int main()
{
	int n,m;
	cin>>n>>m;
	for(int i=0;i<m;i++)
	{
		int x,y;
		cin>>x>>y;
		adj[x].pb(y);
		adj[y].pb(x);
	}
	for(int i=1;i<=n;i++)
		sort(all(adj[i]));
	for(int i=0;i<n+2;i++){
		pa[i]=i;
		size[i]=1;
	}

	int ans=0;
	int fre[n+5]={0};
	set<int>cur;
	for(int i=1;i<=n;i++)
	{
		int v=i;
		vector<int>temp;
		cur.insert(v);
		for(int j=0;j<adj[i].size()&&adj[i][j]<v;j++)
		{
			int u=adj[i][j];
			int papa=find_par(u);
			fre[papa]++;
			temp.pb(papa);
		}
		for(auto j:cur)
		{
			int p1=find_par(v);
			int p2=find_par(j);
			if(p1!=p2 && fre[p2]!=size[p2])
			{
				if(p1>p2)
					swap(p1,p2);
				pa[p2]=p1;
				size[p1]+=size[p2];
				cur.erase(p2);
			}
		}
		for(int j=0;j<temp.size();j++)
			fre[temp[j]]=0;
	}
	set<int>s;
	for(int i=1;i<=n;i++)
		s.insert(find_par(i));
	cout<<s.size()-1<<endl;
	return 0;
}


//Code of C#oder Born_Clear
#include <bits/stdc++.h>
using namespace std;
#define loop(n) for(int i=0;i<n;++i)
#define FORD(i,a,b) for(int i=a;i>=b;--i)
#define pb push_back
#define mp make_pair
#define all(x) x.begin(),x.end()
#define ll long long
#define s(x) scanf("%d", &x)
#define sd(x) scanf("%lf", &x)
#define sl(x) scanf("%lld", &x)
#define mod 1000000007
#define fi first
#define se second
#define p(x) printf("%d",x)
#define pl(x) printf("%lld", x)
#define pd(x) printf("%lf", x)
#define pn() printf("\n")
#define vi(v) vector<int>v
#define vl(v) vector<long long int>v
#define pii pair<int,int>
#define pll pair<long long int,long long int>
#define len(s) s.length()
#define mem1(s) memset(s,-1,sizeof(s))
#define mem(s) memset(s,0,sizeof(s))
void input(int n,int a[]){loop(n)cin>>a[i];}
ll bin_expo(ll A, ll B, ll M){ll res = 1LL;while (B > 0){if(B % 2 == 1){res = (res * A) % M;}A = (A * A) % M; B = B / 2;}return res;}
int pa[100005];int siz[100005];

vector<int>adj[100005];
int find_par(int x)
{
	if(pa[x]==x)
		return x;
	return pa[x]=find_par(pa[x]);
}
int main()
{
	int n,m;
	cin>>n>>m;
	for(int i=0;i<m;i++)
	{
		int x,y;
		cin>>x>>y;
		adj[x].pb(y);
		adj[y].pb(x);
	}
	for(int i=1;i<=n;i++)
		if(adj[i].size()!=0)
			sort(all(adj[i]));
	for(int i=1;i<=n;i++){
		pa[i]=i;
		siz[i]=1;
	}

	int ans=0;
	int fre[n+10];
	for(int i=1;i<=n;i++)fre[i]=0;
	set<int>cur;
	vector<int>temp;
	for(int i=1;i<=n;i++)
	{
		int v=i;
		cur.insert(v);
		temp.clear();
		for(int j=0;j<adj[i].size();j++)
		{
			if(adj[i][j]>v)
				break;
			int u=adj[i][j];
			int papa=find_par(u);
			fre[papa]++;
			temp.pb(papa);
		}
		for(auto j:cur)
		{
			int p1=find_par(v);
			int p2=find_par(j);
			if(p1!=p2 && fre[p2]!=siz[p2])
			{
				if(p1>p2)
					swap(p1,p2);
				pa[p2]=p1;
				siz[p1]+=siz[p2];
				if(cur.find(p2)!=cur.end())
					cur.erase(p2);
			}
		}
		for(int j=0;j<temp.size();j++)
			fre[temp[j]]=0;
	}
	set<int>s;
	for(int i=1;i<=n;i++)
		s.insert(find_par(i));
	ans = ((int)s.size()-1);
	cout<<ans<<endl;
	return 0;
}


//Code of C#oder Born_Clear
#include <bits/stdc++.h>
using namespace std;
#define loop(n) for(int i=0;i<n;++i)
#define FORD(i,a,b) for(int i=a;i>=b;--i)
#define pb push_back
#define mp make_pair
#define all(x) x.begin(),x.end()
#define ll long long
#define s(x) scanf("%d", &x)
#define sd(x) scanf("%lf", &x)
#define sl(x) scanf("%lld", &x)
#define mod 1000000007
#define fi first
#define se second
#define p(x) printf("%d",x)
#define pl(x) printf("%lld", x)
#define pd(x) printf("%lf", x)
#define pn() printf("\n")
#define vi(v) vector<int>v
#define vl(v) vector<long long int>v
#define pii pair<int,int>
#define pll pair<long long int,long long int>
#define len(s) s.length()
#define mem1(s) memset(s,-1,sizeof(s))
#define mem(s) memset(s,0,sizeof(s))
void input(int n,int a[]){loop(n)cin>>a[i];}
ll bin_expo(ll A, ll B, ll M){ll res = 1LL;while (B > 0){if(B % 2 == 1){res = (res * A) % M;}A = (A * A) % M; B = B / 2;}return res;}
int pa[1000000];int size[1000000];

vector<int>adj[1000000];
int find_par(int x)
{
	if(pa[x]==x)
		return x;
	return pa[x]=find_par(pa[x]);
}
int main()
{
	int n,m;
	cin>>n>>m;
	for(int i=0;i<m;i++)
	{
		int x,y;
		cin>>x>>y;
		adj[x].pb(y);
		adj[y].pb(x);
	}
	for(int i=1;i<=n;i++)
		sort(all(adj[i]));
	for(int i=0;i<n+2;i++){
		pa[i]=i;
		size[i]=1;
	}

	int ans=0;
	int fre[n+5]={0};
	set<int>cur;
	for(int i=1;i<=n;i++)
	{
		int v=i;
		vector<int>temp;
		cur.insert(v);
		for(int j=0;j<adj[i].size();j++)
		{
			if(adj[i][j]>v)
				break;
			int u=adj[i][j];
			int papa=find_par(u);
			fre[papa]++;
			temp.pb(papa);
		}
		for(auto j:cur)
		{
			int p1=find_par(v);
			int p2=find_par(j);
			if(p1!=p2 && fre[p2]!=size[p2])
			{
				if(p1>p2)
					swap(p1,p2);
				pa[p2]=p1;
				size[p1]+=size[p2];
				cur.erase(p2);
			}
		}
		for(int j=0;j<temp.size();j++)
			fre[temp[j]]=0;
	}
	set<int>s;
	for(int i=1;i<=n;i++)
		s.insert(find_par(i));
	cout<<s.size()-1<<endl;
	return 0;
}


//Code of C#oder Born_Clear
#include <bits/stdc++.h>
using namespace std;
#define loop(n) for(int i=0;i<n;++i)
#define FORD(i,a,b) for(int i=a;i>=b;--i)
#define pb push_back
#define mp make_pair
#define all(x) x.begin(),x.end()
#define ll long long
#define s(x) scanf("%d", &x)
#define sd(x) scanf("%lf", &x)
#define sl(x) scanf("%lld", &x)
#define mod 1000000007
#define fi first
#define se second
#define p(x) printf("%d",x)
#define pl(x) printf("%lld", x)
#define pd(x) printf("%lf", x)
#define pn() printf("\n")
#define vi(v) vector<int>v
#define vl(v) vector<long long int>v
#define pii pair<int,int>
#define pll pair<long long int,long long int>
#define len(s) s.length()
#define mem1(s) memset(s,-1,sizeof(s))
#define mem(s) memset(s,0,sizeof(s))
void input(int n,int a[]){loop(n)cin>>a[i];}
ll bin_expo(ll A, ll B, ll M){ll res = 1LL;while (B > 0){if(B % 2 == 1){res = (res * A) % M;}A = (A * A) % M; B = B / 2;}return res;}
int pa[1000000];int size[1000000];

vector<int>adj[1000000];
int find_par(int x)
{
	if(pa[x]==x)
		return x;
	return pa[x]=find_par(pa[x]);
}
int main()
{
	int n,m;
	cin>>n>>m;
	for(int i=0;i<m;i++)
	{
		int x,y;
		cin>>x>>y;
		adj[x].pb(y);
		adj[y].pb(x);
	}
	for(int i=1;i<=n;i++)
		if(adj[i].size()!=0)
			sort(all(adj[i]));
	for(int i=0;i<n+2;i++){
		pa[i]=i;
		size[i]=1;
	}

	int ans=0;
	int fre[n+5]={0};
	set<int>cur;
	for(int i=1;i<=n;i++)
	{
		int v=i;
		vector<int>temp;
		cur.insert(v);
		for(int j=0;j<adj[i].size();j++)
		{
			if(adj[i][j]>v)
				break;
			int u=adj[i][j];
			int papa=find_par(u);
			fre[papa]++;
			temp.pb(papa);
		}
		for(auto j:cur)
		{
			int p1=find_par(v);
			int p2=find_par(j);
			if(p1!=p2 && fre[p2]!=size[p2])
			{
				if(p1>p2)
					swap(p1,p2);
				pa[p2]=p1;
				size[p1]+=size[p2];
				if(cur.find(p2)!=cur.end())
					cur.erase(p2);
			}
		}
		for(int j=0;j<temp.size();j++)
			fre[temp[j]]=0;
	}
	set<int>s;
	for(int i=1;i<=n;i++)
		s.insert(find_par(i));
	cout<<s.size()-1<<endl;
	return 0;
}


//Code of C#oder Born_Clear
#include <bits/stdc++.h>
using namespace std;
#define loop(n) for(int i=0;i<n;++i)
#define FORD(i,a,b) for(int i=a;i>=b;--i)
#define pb push_back
#define mp make_pair
#define all(x) x.begin(),x.end()
#define ll long long
#define s(x) scanf("%d", &x)
#define sd(x) scanf("%lf", &x)
#define sl(x) scanf("%lld", &x)
#define mod 1000000007
#define fi first
#define se second
#define p(x) printf("%d",x)
#define pl(x) printf("%lld", x)
#define pd(x) printf("%lf", x)
#define pn() printf("\n")
#define vi(v) vector<int>v
#define vl(v) vector<long long int>v
#define pii pair<int,int>
#define pll pair<long long int,long long int>
#define len(s) s.length()
#define mem1(s) memset(s,-1,sizeof(s))
#define mem(s) memset(s,0,sizeof(s))
void input(int n,int a[]){loop(n)cin>>a[i];}
ll bin_expo(ll A, ll B, ll M){ll res = 1LL;while (B > 0){if(B % 2 == 1){res = (res * A) % M;}A = (A * A) % M; B = B / 2;}return res;}
int pa[1000000];int size[1000000];

vector<int>adj[1000000];
int find_par(int x)
{
	if(pa[x]==x)
		return x;
	return pa[x]=find_par(pa[x]);
}
int main()
{
	int n,m;
	cin>>n>>m;
	for(int i=0;i<m;i++)
	{
		int x,y;
		cin>>x>>y;
		adj[x].pb(y);
		adj[y].pb(x);
	}
	for(int i=1;i<=n;i++)
		if(adj[i].size()!=0)
			sort(all(adj[i]));
	for(int i=0;i<n+2;i++){
		pa[i]=i;
		size[i]=1;
	}

	int ans=0;
	int fre[n+10];
	for(int i=0;i<n+6;i++)fre[i]=0;
	set<int>cur;
	for(int i=1;i<=n;i++)
	{
		int v=i;
		vector<int>temp;
		cur.insert(v);
		for(int j=0;j<adj[i].size();j++)
		{
			if(adj[i][j]>v)
				break;
			int u=adj[i][j];
			int papa=find_par(u);
			fre[papa]++;
			temp.pb(papa);
		}
		for(auto j:cur)
		{
			int p1=find_par(v);
			int p2=find_par(j);
			if(p1!=p2 && fre[p2]!=size[p2])
			{
				if(p1>p2)
					swap(p1,p2);
				pa[p2]=p1;
				size[p1]+=size[p2];
				if(cur.find(p2)!=cur.end())
					cur.erase(p2);
			}
		}
		for(int j=0;j<temp.size();j++)
			fre[temp[j]]=0;
	}
	set<int>s;
	for(int i=1;i<=n;i++)
		s.insert(find_par(i));
	ans = ((int)s.size()-1);
	cout<<ans<<endl;
	return 0;
}


#include <bits/stdc++.h>

using namespace std;

const int MAX_N = 1e5 + 1;

int N, M;
vector<int> graph[MAX_N];
int root[MAX_N], cnt[MAX_N], U[MAX_N], V[MAX_N];

int find_root(int u)
{
    while (u != root[u]) u = root[u];
    return root[u];
}

bool try_merge(int u, int v)
{
    u = find_root(u);
    v = find_root(v);

    if (u != v)
    {
        if (cnt[u] == cnt[v]) cnt[u]++;
        if (cnt[u] > cnt[v]) root[v] = u;
        else root[u] = v;

        return true;
    }

    return false;
}

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(NULL); cout.tie(NULL);

    cin >> N >> M;
    for (int i = 1; i <= M; i++)
    {
        cin >> U[i] >> V[i];
        graph[U[i]].push_back(V[i]);
        graph[V[i]].push_back(U[i]);
    }

    for (int i = 1; i <= N; i++)
    {
        root[i] = i;
    }

    for (int u = 1; u <= N; u++)
    {
        if (root[u] != u) continue;

        vector<bool> present(N + 1);
        present[u] = true;
        for (int v : graph[u])
        {
            present[v] = true;
        }

        for (int v = 1; v <= N; v++)
        {
            if (!present[v])
            {
                int r = find_root(u);
                root[v] = r;
                cnt[r]++;
            }
        }
    }

    int mst = 0;
    for (int i = 1; i <= M; i++)
    {
        int u = U[i];
        int v = V[i];

        if (try_merge(u, v)) mst++;
    }

    cout << mst;

    return 0;
}


#include <bits/stdc++.h>

using namespace std;

const int MAX_N = 1e5 + 1;

int N, M;
set<int> graph[MAX_N];
int root[MAX_N], cnt[MAX_N], U[MAX_N], V[MAX_N];

int find_root(int u)
{
    while (u != root[u])
        u = root[u];
    return root[u];
}

bool try_merge(int u, int v)
{
    u = find_root(u);
    v = find_root(v);

    if (u != v)
    {
        if (cnt[u] == cnt[v])
            cnt[u]++;
        if (cnt[u] > cnt[v])
            root[v] = u;
        else
            root[u] = v;

        return true;
    }

    return false;
}

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);

    cin >> N >> M;
    for (int i = 1; i <= M; i++)
    {
        cin >> U[i] >> V[i];
        graph[U[i]].insert(V[i]);
        graph[V[i]].insert(U[i]);
    }

    for (int i = 1; i <= N; i++)
    {
        root[i] = i;
    }

    for (int u = 1; u <= N; u++)
    {
        for (int v = u + 1, c = 1; v <= N && c <= 20; v++)
        {
            if (graph[u].find(v) == graph[u].end())
            {
                c++;
                try_merge(u, v);
            }
        }
    }

    set<int> components;
    for (int i = 1; i <= N; i++)
        components.insert(find_root(i));

    int sz = components.size();
    int mst = sz - 1;

    cout << mst;

    return 0;
}


#include <bits/stdc++.h>

using namespace std;

const int MAX_N = 1e5 + 1;

int N, M;
vector<int> graph[MAX_N];
int root[MAX_N], cnt[MAX_N], U[MAX_N], V[MAX_N];

int find_root(int u)
{
    while (u != root[u]) u = root[u];
    return root[u];
}

bool try_merge(int u, int v)
{
    u = find_root(u);
    v = find_root(v);

    if (u != v)
    {
        if (cnt[u] == cnt[v]) cnt[u]++;
        if (cnt[u] > cnt[v]) root[v] = u;
        else root[u] = v;

        return true;
    }

    return false;
}

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(NULL); cout.tie(NULL);

    cin >> N >> M;
    for (int i = 1; i <= M; i++)
    {
        cin >> U[i] >> V[i];
        graph[U[i]].push_back(V[i]);
        graph[V[i]].push_back(U[i]);
    }

    for (int i = 1; i <= N; i++)
    {
        root[i] = i;
    }

    for (int u = 1; u <= N; u++)
    {
        if (find_root(u) != u) continue;

        vector<bool> present(N + 1);
        present[u] = true;
        for (int v : graph[u])
        {
            present[v] = true;
        }

        for (int v = 1; v <= N; v++)
        {
            if (!present[v])
            {
                try_merge(u, v);
            }
        }
    }

    set<int> components;
    for (int i = 1; i <= N; i++) components.insert(find_root(i));

    int sz = components.size();
    int mst = sz - 1;

    cout << mst;

    return 0;
}


#include <bits/stdc++.h>

using namespace std;

const int MAX_N = 1e5 + 1;

int N, M;
vector<int> graph[MAX_N];
int root[MAX_N], cnt[MAX_N], U[MAX_N], V[MAX_N];

int find_root(int u)
{
    while (u != root[u]) u = root[u];
    return root[u];
}

bool try_merge(int u, int v)
{
    u = find_root(u);
    v = find_root(v);

    if (u != v)
    {
        if (cnt[u] == cnt[v]) cnt[u]++;
        if (cnt[u] > cnt[v]) root[v] = u;
        else root[u] = v;

        return true;
    }

    return false;
}

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(NULL); cout.tie(NULL);

    cin >> N >> M;
    for (int i = 1; i <= M; i++)
    {
        cin >> U[i] >> V[i];
        graph[U[i]].push_back(V[i]);
        graph[V[i]].push_back(U[i]);
    }

    for (int i = 1; i <= N; i++)
    {
        root[i] = i;
    }

    for (int u = 1; u <= N; u++)
    {
        if (root[u] != u) continue;

        vector<bool> present(N + 1);
        present[u] = true;
        for (int v : graph[u])
        {
            present[v] = true;
        }

        for (int v = 1; v <= N; v++)
        {
            if (!present[v])
            {
                try_merge(u, v);
            }
        }
    }

    int mst = 0;
    for (int i = 1; i <= M; i++)
    {
        int u = U[i];
        int v = V[i];

        if (try_merge(u, v)) mst++;
    }

    cout << mst;

    return 0;
}


#include <bits/stdc++.h>

using namespace std;

const int MAX_N = 1e5 + 1;

int N, M;
vector<int> graph[MAX_N];
int U[MAX_N], V[MAX_N];
bool visited[MAX_N];

bool present[MAX_N];

queue<int> q;

void bfs(int a)
{
    q.push(a);

    while (!q.empty())
    {
        int u = q.front();
        q.pop();

        visited[u] = true;

        for (int v = 1; v <= N; v++)
        {
            present[v] = false;
        }

        for (int v : graph[u])
        {
            present[v] = true;
        }

        for (int v = 1; v <= N; v++)
        {
            if (!present[v] && !visited[v])
            {
                visited[v] = true;
                q.push(v);
            }
        }
    }
}

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(NULL); cout.tie(NULL);

    cin >> N >> M;
    for (int i = 1; i <= M; i++)
    {
        cin >> U[i] >> V[i];
        graph[U[i]].push_back(V[i]);
        graph[V[i]].push_back(U[i]);
    }

    int components = 0;

    for (int u = 1; u <= N; u++)
    {
        if (visited[u]) continue;

        components++;
        bfs(u);
    }

    int mst = components - 1;

    cout << mst;

    return 0;
}


#include <bits/stdc++.h>

using namespace std;

const int MAX_N = 1e5 + 1;

int N, M;
vector<int> graph[MAX_N];
int root[MAX_N], cnt[MAX_N], U[MAX_N], V[MAX_N];

int find_root(int u)
{
    while (u != root[u]) u = root[u];
    return root[u];
}

bool try_merge(int u, int v)
{
    u = find_root(u);
    v = find_root(v);

    if (u != v)
    {
        if (cnt[u] == cnt[v]) cnt[u]++;
        if (cnt[u] > cnt[v]) root[v] = u;
        else root[u] = v;

        return true;
    }

    return false;
}

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(NULL); cout.tie(NULL);

    cin >> N >> M;
    for (int i = 1; i <= M; i++)
    {
        cin >> U[i] >> V[i];
        graph[U[i]].push_back(V[i]);
        graph[V[i]].push_back(U[i]);
    }

    for (int i = 1; i <= N; i++)
    {
        root[i] = i;
    }

    for (int u = 1; u <= N; u++)
    {
        if (root[u] != u) continue;

        vector<bool> present(N + 1);
        present[u] = true;
        for (int v : graph[u])
        {
            present[v] = true;
        }

        for (int v = 1; v <= N; v++)
        {
            if (!present[v])
            {
                try_merge(u, v);
            }
        }
    }

    set<int> components;
    for (int i = 1; i <= N; i++) components.insert(find_root(i));

    int sz = components.size();
    int mst = sz - 1;

    cout << mst;

    return 0;
}


#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(NULL); cout.tie(NULL);

    ll N, M;
    cin >> N >> M;

    ll total = (N*(N - 1)) / 2;
    ll zero_edges = total - M;

    if (zero_edges >= N-1) cout << 0;
    else cout << N-1 - zero_edges;

    return 0;
}


#include <bits/stdc++.h>

using namespace std;

const int MAX_N = 1e5 + 1;

int N, M;
vector<int> graph[MAX_N];
int root[MAX_N], cnt[MAX_N], U[MAX_N], V[MAX_N];

int find_root(int u)
{
    while (u != root[u]) u = root[u];
    return root[u];
}

bool try_merge(int u, int v)
{
    u = find_root(u);
    v = find_root(v);

    if (u != v)
    {
        if (cnt[u] == cnt[v]) cnt[u]++;
        if (cnt[u] > cnt[v]) root[v] = u;
        else root[u] = v;

        return true;
    }

    return false;
}

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(NULL); cout.tie(NULL);

    cin >> N >> M;
    for (int i = 1; i <= M; i++)
    {
        cin >> U[i] >> V[i];
        graph[U[i]].push_back(V[i]);
        graph[V[i]].push_back(U[i]);
    }

    for (int i = 1; i <= N; i++)
    {
        root[i] = i;
    }

    for (int u = 1; u <= N; u++)
    {
        if (root[u] != u) continue;

        vector<bool> present(N + 1);
        present[u] = true;
        for (int v : graph[u])
        {
            present[v] = true;
        }

        for (int v = 1; v <= N; v++)
        {
            if (!present[v])
            {
                int r = find_root(v);
                root[r] = u;
                cnt[u]++;
            }
        }
    }

    int mst = 0;
    for (int i = 1; i <= M; i++)
    {
        int u = U[i];
        int v = V[i];

        if (try_merge(u, v)) mst++;
    }

    cout << mst;

    return 0;
}


#include <bits/stdc++.h>

using namespace std;

const int MAX_N = 1e5 + 1;

int N, M;
vector<int> graph[MAX_N];
int root[MAX_N], cnt[MAX_N], U[MAX_N], V[MAX_N];

int find_root(int u)
{
    while (u != root[u])
        u = root[u];
    return root[u];
}

bool try_merge(int u, int v)
{
    u = find_root(u);
    v = find_root(v);

    if (u != v)
    {
        if (cnt[u] == cnt[v])
            cnt[u]++;
        if (cnt[u] > cnt[v])
            root[v] = u;
        else
            root[u] = v;

        return true;
    }

    return false;
}

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);

    cin >> N >> M;
    for (int i = 1; i <= M; i++)
    {
        cin >> U[i] >> V[i];
        graph[U[i]].push_back(V[i]);
        graph[V[i]].push_back(U[i]);
    }

    for (int i = 1; i <= N; i++)
    {
        root[i] = i;
    }

    for (int u = 1; u <= N; u++)
    {
        vector<bool> present(N + 1);
        present[u] = true;
        for (int v : graph[u])
        {
            present[v] = true;
        }

        for (int v = 1; v <= N; v++)
        {
            if (!present[v])
            {
                try_merge(u, v);
            }
        }
    }

    set<int> components;
    for (int i = 1; i <= N; i++)
        components.insert(find_root(i));

    int sz = components.size();
    int mst = sz - 1;

    cout << mst;

    return 0;
}


#include <bits/stdc++.h>

using namespace std;

const int MAX_N = 1e5 + 1;

int N, M;
vector<int> graph[MAX_N];
int root[MAX_N], cnt[MAX_N], U[MAX_N], V[MAX_N];

int find_root(int u)
{
    while (u != root[u]) u = root[u];
    return root[u];
}

bool try_merge(int u, int v)
{
    u = find_root(u);
    v = find_root(v);

    if (u != v)
    {
        if (cnt[u] == cnt[v]) cnt[u]++;
        if (cnt[u] > cnt[v]) root[v] = u;
        else root[u] = v;

        return true;
    }

    return false;
}

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(NULL); cout.tie(NULL);

    cin >> N >> M;
    for (int i = 1; i <= M; i++)
    {
        cin >> U[i] >> V[i];
        graph[U[i]].push_back(V[i]);
        graph[V[i]].push_back(U[i]);
    }

    for (int i = 1; i <= N; i++)
    {
        root[i] = i;
    }

    for (int u = 1; u <= N; u++)
    {
        if (root[u] != u) continue;

        vector<bool> present(N + 1);
        present[u] = true;
        for (int v : graph[u])
        {
            present[v] = true;
        }

        for (int v = 1; v <= N; v++)
        {
            if (!present[v])
            {
                root[v] = u;
                cnt[u]++;
            }
        }
    }

    int mst = 0;
    for (int i = 1; i <= M; i++)
    {
        int u = U[i];
        int v = V[i];

        if (try_merge(u, v)) mst++;
    }

    cout << mst;

    return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define ff first
#define ss second
#define pb push_back
#define mp make_pair
#define ld long double
#define f(i,x,n) for(int i=x;i<n;i++)
#define int long long
#define mod 1000000007
#define endl "\n"
const int INF = 1e18;
void fastio()
{
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
}
vector<int>vc[100001];
int prt[100001];
int fpr(int x)
{
	if(prt[x]==x)
		return x;
	else
		return prt[x]=fpr(prt[x]);
}
int32_t main()
{
	fastio();
	f(i,0,100002)
	prt[i]=i;
	int n,m;
	cin>>n>>m;
	f(i,0,m)
	{
		int a,b;
		cin>>a>>b;
		vc[a].pb(b);
		vc[b].pb(a);
	}
	set<int>se;
	f(i,1,n+1)
	se.insert(i);
	f(i,1,n+1)
	{
		set<int>ss;
		f(j,0,vc[i].size())
		{
			int tt=fpr(vc[i][j]);
			if(se.count(tt))
				ss.insert(vc[i][j]);
		}
		for(auto j=se.begin();j!=se.end();j++)
		{
			if(ss.count(*j)==0)
			{
				int a1=*j;
				int p1=fpr(a1);
				int p2=fpr(i);
				if(p1!=p2)
				prt[p1]=p2;
			}
		}
		se.clear();
		for(auto j=ss.begin();j!=ss.end();j++)
		{
			int aa=fpr(*j);
			se.insert(aa);
		}
	}
	int ans=0;
	f(i,1,n+1)
	{
		if(prt[i]==i)
			ans++;
	}
	cout<<ans-1;
}


#include<bits/stdc++.h>
using namespace std;
#define ff first
#define ss second
#define pb push_back
#define mp make_pair
#define ld long double
#define f(i,x,n) for(int i=x;i<n;i++)
#define int long long
#define mod 1000000007
#define endl "\n"
const int INF = 1e18;
void fastio()
{
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
}
vector<int>vc[100001];
int prt[100001];
int fpr(int x)
{
	if(prt[x]==x)
		return x;
	else
		return prt[x]=fpr(prt[x]);
}
int32_t main()
{
	fastio();
	f(i,0,100002)
	prt[i]=i;
	int n,m;
	cin>>n>>m;
	f(i,0,m)
	{
		int a,b;
		cin>>a>>b;
		vc[a].pb(b);
		vc[b].pb(a);
	}
	multiset<int>se;
	f(i,1,n+1)
	se.insert(i);
	f(i,1,n+1)
	{
		multiset<int>ss;
		if(se.count(i))
		se.erase(i);
		f(j,0,vc[i].size())
		{
			if(se.count(vc[i][j]))
				ss.insert(vc[i][j]);
		}
		for(auto j=se.begin();j!=se.end();j++)
		{
			if(ss.count(*j)==0)
			{
				int a1=*j;
				int p1=fpr(a1);
				int p2=fpr(i);
				if(p1!=p2)
				prt[p1]=p2;
				ss.insert(p2);
			}
		}
		se.clear();
		for(auto j=ss.begin();j!=ss.end();j++)
		{
			se.insert(*j);
		}
	}
	int ans=0;
	f(i,1,n+1)
	{
		if(prt[i]==i)
			ans++;
	}
	cout<<ans-1;
}


#include<bits/stdc++.h>
using namespace std;
#define ff first
#define ss second
#define pb push_back
#define mp make_pair
#define ld long double
#define f(i,x,n) for(int i=x;i<n;i++)
#define int long long
#define mod 1000000007
#define endl "\n"
const int INF = 1e18;
void fastio()
{
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
}
vector<int>vc[100001];
int prt[100001];
int fpr(int x)
{
	if(prt[x]==x)
		return x;
	else
		return prt[x]=fpr(prt[x]);
}
int32_t main()
{
	fastio();
	f(i,0,100002)
	prt[i]=i;
	int n,m;
	cin>>n>>m;
	f(i,0,m)
	{
		int a,b;
		cin>>a>>b;
		vc[a].pb(b);
		vc[b].pb(a);
	}
	set<int>se;
	f(i,1,n+1)
	se.insert(i);
	f(i,1,n+1)
	{
		set<int>ss;
		f(j,0,vc[i].size())
		{
			if(se.count(vc[i][j]))
				ss.insert(vc[i][j]);
		}
		for(auto j=se.begin();j!=se.end();j++)
		{
			if(ss.count(*j)==0)
			{
				int a1=*j;
				int p1=fpr(a1);
				int p2=fpr(i);
				if(p1!=p2)
				prt[p1]=p2;
			}
		}
		se.clear();
		for(auto j=ss.begin();j!=ss.end();j++)
		{
			int aa=fpr(*j);
			se.insert(aa);
		}
	}
	int ans=0;
	f(i,1,n+1)
	{
		if(prt[i]==i)
			ans++;
	}
	cout<<ans-1;
}


#include<bits/stdc++.h>
using namespace std;
#define ff first
#define ss second
#define pb push_back
#define mp make_pair
#define ld long double
#define f(i,x,n) for(int i=x;i<n;i++)
#define int long long
#define mod 1000000007
#define endl "\n"
const int INF = 1e18;
void fastio()
{
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
}
vector<int>vc[100001];
int vst[100001];
set<int>se;
int dfs(int x)
{
	se.erase(x);
	vst[x]=1;
	vector<int>vv;
	for(auto i:vc[x])
	{
		if(se.count(i))
		{
			se.erase(i);
			vv.pb(i);
		}
	}
	vector<int>vt;
	for(auto i=se.begin();i!=se.end();i++)
	{
		vt.pb(*i);
	}
	se.clear();
	f(i,0,vv.size())
	se.insert(vv[i]);
	f(i,0,vt.size())
	dfs(vt[i]);
}
int32_t main()
{
	fastio();
	int n,m;
	cin>>n>>m;
	f(i,0,m)
	{
		int a,b;
		cin>>a>>b;
		vc[a].pb(b);
		vc[b].pb(a);
	}
	f(i,1,n+1)
	se.insert(i);
	int ans=0;
	f(i,1,n+1)
	{
		if(vst[i]==0)
		{
			ans++;
			dfs(i);
		}
	}
	cout<<ans-1;
}


#include<bits/stdc++.h>
using namespace std;
#define ff first
#define ss second
#define pb push_back
#define mp make_pair
#define ld long double
#define f(i,x,n) for(int i=x;i<n;i++)
#define int long long
#define mod 1000000007
#define endl "\n"
const int INF = 1e18;
void fastio()
{
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
}
vector<int>vc[100001];
int prt[100001];
int fpr(int x)
{
	if(prt[x]==x)
		return x;
	else
		return prt[x]=fpr(prt[x]);
}
int32_t main()
{
	fastio();
	f(i,0,100002)
	prt[i]=i;
	int n,m;
	cin>>n>>m;
	f(i,0,m)
	{
		int a,b;
		cin>>a>>b;
		vc[a].pb(b);
		vc[b].pb(a);
	}
	set<int>se;
	f(i,1,n+1)
	se.insert(i);
	f(i,1,n+1)
	{
		set<int>ss;
		f(j,0,vc[i].size())
		{
			if(se.count(vc[i][j]))
				ss.insert(vc[i][j]);
		}
		for(auto j=se.begin();j!=se.end();j++)
		{
			if(ss.count(*j)==0)
			{
				int a1=*j;
				int p1=fpr(a1);
				int p2=fpr(i);
				if(p1!=p2)
				prt[p1]=p2;
			}
		}
		se.clear();
		for(auto j=se.begin();j!=se.end();j++)
		{
			int aa=fpr(*j);
			se.insert(aa);
		}
	}
	int ans=0;
	f(i,1,n+1)
	{
		if(prt[i]==i)
			ans++;
	}
	cout<<ans-1;
}


#include<bits/stdc++.h>
using namespace std;
#define ff first
#define ss second
#define pb push_back
#define mp make_pair
#define ld long double
#define f(i,x,n) for(int i=x;i<n;i++)
#define int long long
#define mod 1000000007
#define endl "\n"
const int INF = 1e18;
void fastio()
{
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
}
vector<int>vc[100001];
int prt[100001];
int fpr(int x)
{
	if(prt[x]==x)
		return x;
	else
		return prt[x]=fpr(prt[x]);
}
int32_t main()
{
	fastio();
	f(i,0,100001)
	prt[i]=i;
	int n,m;
	cin>>n>>m;
	f(i,0,m)
	{
		int a,b;
		cin>>a>>b;
		vc[a].pb(b);
		vc[b].pb(a);
	}
	set<int>se;
	f(i,1,n+1)
	se.insert(i);
	f(i,1,n+1)
	{
		set<int>ss;
		if(se.count(i))
		se.erase(i);
		f(j,0,vc[i].size())
		{
			if(se.count(vc[i][j]))
				ss.insert(vc[i][j]);
		}
		for(auto j=se.begin();j!=se.end();j++)
		{
			if(!ss.count(*j))
			{
				int a1=*j;
				int p1=fpr(a1);
				int p2=fpr(i);
				prt[p1]=p2;
			}
		}
		se.clear();
		for(auto j=ss.begin();j!=ss.end();j++)
		{
			se.insert(*j);
		}
	}
	int ans=0;
	f(i,1,n+1)
	{
		if(prt[i]==i)
			ans++;
	}
	cout<<ans-1;
}


#include <bits/stdc++.h>
using namespace std;const int k=2e5+10;unordered_map<int,bool> g[k];bitset<k> used;void dfs(int v){used[v]=0;for(int i=used._Find_first();i<used.size();i=used._Find_next(i)) if(!g[v][i]) dfs(i);}int main(){int n,m,a,b,cnt=0;cin>>n>>m;for (int i=0;i<n;i++) used[i]=1;for (int i=0; i<m; i++){cin>>a>>b;a--;b--;g[a][b]=g[b][a]=1;}for (int i=0; i<n; i++){if (used[i]){dfs(i);cnt++;}}cout<<cnt-1;}


#include <bits/stdc++.h>

using namespace std;

vector <int> g[100001];
bool used[100001]= {0};

void dfs(int v,int n)
{
    bool check[n]= {0};
    used[v]=1;
    check[v]=1;
    for (int i=0; i<g[v].size(); i++)
    {
        check[g[v][i]]=1;
    }
    for (int i=0; i<n; i++)
    {
        if (!check[i]&&!used[i])
        {
            dfs(i,n);
        }
    }
}

int main()
{
    int n,m,a,b,cnt=0;
    cin>>n>>m;
    for (int i=0; i<m; i++)
    {
        cin>>a>>b;
        g[a-1].push_back(b-1);
        g[b-1].push_back(a-1);
    }
    for (int i=0; i<n; i++)
    {
        if (!used[i])
        {
            dfs(i,n);
            cnt++;
        }
    }
    cout<<cnt-1;

    return 0;
}


#include <bits/stdc++.h>

using namespace std;

unordered_map<int,bool> g[100001];
bitset<100001> used;
void dfs(int v,int n)
{
    used[v]=1;
    for (int i=0; i<n; i++)
    {
        if (!g[v][i]&&!used[i])
        {
            dfs(i,n);
        }
    }
}

int main()
{
    int n,m,a,b,cnt=0;
    cin>>n>>m;
    for (int i=0; i<m; i++)
    {
        cin>>a>>b;
        a--;
        b--;
        g[a][b]=g[b][a]=1;
    }
    for (int i=0; i<n; i++)
    {
        if (!used[i])
        {
            dfs(i,n);
            cnt++;
        }
    }
    cout<<cnt-1;
cout<<2e5;

    return 0;
}


#include <bits/stdc++.h>

using namespace std;

bool used[100001]={0};
unordered_map<int,bool> g[100001];
void dfs(int v,int n)
{
    used[v]=1;
    for (int i=0; i<n; i++)
    {
        if (!g[v][i]&&!used[i])
        {
            dfs(i,n);
        }
    }
}

int main()
{
    int n,m,a,b,cnt=0;
    cin>>n>>m;
    for (int i=0; i<m; i++)
    {
        cin>>a>>b;
        a--;
        b--;
        g[a][b]=g[b][a]=1;
    }
    for (int i=0; i<n; i++)
    {
        if (!used[i])
        {
            dfs(i,n);
            cnt++;
        }
    }
    cout<<cnt-1;

    return 0;
}


#include <bits/stdc++.h>

using namespace std;

int main()
{
int n,m,a,b,sum=0,way;
cin>>n>>m;
vector <int> g[n];
for (int i=0;i<m;i++){
    cin>>a>>b;
    g[a-1].push_back(b-1);
    g[b-1].push_back(a-1);
}
int ind=0;
for (int i=1;i<n;i++){
way=1;
for (int j=0;j<i;j++){
    bool res=0;
    for (int k=0;k<g[j].size();k++){
        if (g[j][k]==i){
            res=1;
            }

    }
    if (res==0) {
            way=0;
    j=i;
    }

}
sum+=way;

}

cout<<sum;

    return 0;
}


#include <bits/stdc++.h>
using namespace std;const int k=2e5+10;unordered_map<int,bool> g[k];bitset<k> used;void dfs(int v){used[v]=0;for(int i=used._Find_first();i<used.size();i=used._Find_next(i)) if(!g[v][i]) dfs(i);}
int main(){int n,m,a,b,cnt=0;cin>>n>>m;for (int i=0;i<n;i++) used[i]=1;for (int i=0; i<m; i++){cin>>a>>b;a--;b--;g[a][b]=g[b][a]=1;}for (int i=0; i<n; i++){if (used[i]){dfs(i);cnt++;}}cout<<cnt-1;}


#include <bits/stdc++.h>

using namespace std;

int main()
{
    int n,m,a,b,sum=0,way;
    cin>>n>>m;
    vector <int> g[n];
    for (int i=0; i<m; i++)
    {
        cin>>a>>b;
        g[a-1].push_back(b-1);
        g[b-1].push_back(a-1);
    }
    int ind=0;
    bool used[n]= {0};
    used[0]=1;
    for (int k=0; k<n-1; k++)
    {
        int way=1;
        for (int i=0; i<n; i++)
        {
            if (used[i])
            {
                int check[n]= {0};
                for (int j=0; j<g[i].size(); j++)
                {
                    check[g[i][j]]=1;
                }
                for (int j=0; j<n; j++)
                {
                    if (!check[j]&&!used[j])
                    {
                        used[j]=1;
                        way=0;
                        j=n;
                        i=n;
                    }
                }
            }
        }
        if (way==1)
        {
            for (int i=0; i<n; i++)
            {
                if (!used[i])
                {
                    used[i]=1;
                    break;
                }
            }

        }
        sum+=way;
    }

    cout<<sum;

    return 0;
}


#include <bits/stdc++.h>

using namespace std;

unordered_map<int,bool> g[100001];
bitset<100001> used;
void dfs(int v,int n)
{
    used[v]=1;
    for (int i=0; i<n; i++)
    {
        if (!g[v][i]&&!used[i])
        {
            dfs(i,n);
        }
    }
}

int main()
{
    int n,m,a,b,cnt=0;
    cin>>n>>m;
    for (int i=0; i<m; i++)
    {
        cin>>a>>b;
        a--;
        b--;
        g[a][b]=g[b][a]=1;
    }
    for (int i=0; i<n; i++)
    {
        if (!used[i])
        {
            dfs(i,n);
            cnt++;
        }
    }
    cout<<cnt-1;

    return 0;
}


#include <bits/stdc++.h>

using namespace std;

vector <int> g[100000];
bool used[100000]= {0};

void dfs(int v,int n)
{
    bool check[n]= {0};
    used[v]=1;
    check[v]=1;
    for (int i=0; i<g[v].size(); i++)
    {
        check[g[v][i]]=1;
    }
    for (int i=0; i<n; i++)
    {
        if (!check[i]&&!used[i])
        {
            dfs(i,n);
        }
    }
}

int main()
{
    int n,m,a,b,cnt=0;
    cin>>n>>m;
    for (int i=0; i<m; i++)
    {
        cin>>a>>b;
        g[a-1].push_back(b-1);
        g[b-1].push_back(a-1);
    }
    for (int i=0; i<n; i++)
    {
        if (!used[i])
        {
            dfs(i,n);
            cnt++;
        }
    }
    cout<<cnt-1;

    return 0;
}


#include <bits/stdc++.h>

using namespace std;

bool used[100001]= {0};
int mas[100001][2];
void dfs(int v,int n,int m)
{
    bool check[n]= {0};
    used[v]=1;
    check[v]=1;
    for (int i=0; i<m; i++)
    {
        if (mas[i][0]==v) check[mas[i][1]]=1;
        if (mas[i][1]==v) check[mas[i][0]]=1;
    }
    for (int i=0; i<n; i++)
    {
        if (!check[i]&&!used[i])
        {
            dfs(i,n,m);
        }
    }
}

int main()
{
    int n,m,a,b,cnt=0;
    cin>>n>>m;
    for (int i=0; i<m; i++)
    {
        cin>>mas[i][0]>>mas[i][1];
        mas[i][0]--;
        mas[i][1]--;
    }
    for (int i=0; i<n; i++)
    {
        if (!used[i])
        {
            dfs(i,n,m);
            cnt++;
        }
    }
    cout<<cnt-1;

    return 0;
}


#include <bits/stdc++.h>

using namespace std;

vector <int> g[100001];
bool used[100001]= {0};
int mas[100001][2];
void dfs(int v,int n,int m)
{
    bool check[n]= {0};
    used[v]=1;
    check[v]=1;
    for (int i=0; i<m; i++)
    {
        if (mas[i][0]==v) check[mas[i][1]]=1;
        if (mas[i][1]==v) check[mas[i][0]]=1;
    }
    for (int i=0; i<n; i++)
    {
        if (!check[i]&&!used[i])
        {
            dfs(i,n,m);
        }
    }
}

int main()
{
    int n,m,a,b,cnt=0;
    cin>>n>>m;
    for (int i=0; i<m; i++)
    {
        cin>>mas[i][0]>>mas[i][1];
        mas[i][0]--;
        mas[i][1]--;
    }
    for (int i=0; i<n; i++)
    {
        if (!used[i])
        {
            dfs(i,n,m);
            cnt++;
        }
    }
    cout<<cnt-1;

    return 0;
}


#include <bits/stdc++.h>

using namespace std;
const int k=2e5+10;
unordered_map<int,bool> g[k];
bitset<k> used;
void dfs(int v,int n)
{
    used[v]=1;
    for (int i=0; i<n; i++)
    {
        if (!g[v][i]&&!used[i])
        {
            dfs(i,n);
        }
    }
}

int main()
{
    int n,m,a,b,cnt=0;
    cin>>n>>m;
    for (int i=0; i<m; i++)
    {
        cin>>a>>b;
        a--;
        b--;
        g[a][b]=g[b][a]=1;
    }
    for (int i=0; i<n; i++)
    {
        if (!used[i])
        {
            dfs(i,n);
            cnt++;
        }
    }
    cout<<cnt-1;

    return 0;
}


#include <bits/stdc++.h>

using namespace std;
const int k=2e5+10;
unordered_map<int,bool> g[k];
bitset<k> used;
void dfs(int v)
{
    used[v]=0;
    for(int i=used._Find_first();i<used.size();i=used._Find_next(i)) if(!g[v][i]) dfs(i);
}

int main()
{
    int n,m,a,b,cnt=0;
    cin>>n>>m;
    for (int i=0;i<n;i++) used[i]=1;
    for (int i=0; i<m; i++)
    {
        cin>>a>>b;
        a--;
        b--;
        g[a][b]=g[b][a]=1;
    }
    for (int i=0; i<n; i++)
    {
        if (used[i])
        {
            dfs(i);
            cnt++;
        }
    }
    cout<<cnt-1;

    return 0;
}


#include<bits/stdc++.h>
#define N 100005

using namespace std;

int n, m;
set<int> s[N];
int vis[N];
int ans;
int total;

void dfs(int now, int cnt) {
    vis[now]=1;
    ++total;
    for(int i=0;i<n;++i) {
        if(total==n||(cnt==n-1-s[now].size())) break;
        if(vis[i]) continue;
        if(s[now].find(i)==s[now].end()) {
            ans--;
            dfs(i,1);
            ++cnt;
        }
    }
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> n >> m;
    for(int i=0;i<m;++i) {
        int u, v;
        cin >> u >> v;
        u--; v--;
        s[u].insert(v);
        s[v].insert(u);
    }
    ans=n-1;
    total=0;
    for(int i=0;i<n;++i)
        if(vis[i]==0) dfs(i,0);

    cout << ans << endl;

}


#include<bits/stdc++.h>
#define N 100005

using namespace std;

int n, m;
set<int> s[N];
list<int> l;
int vis[N];
int ans;
int total;

int dfs(int now, int cnt) {
    vis[now]=1;
    ++total;
	int del=0;
	int idx=0;
	int remain=l.size();
    for(auto it=l.begin();idx+del<=remain&&it!=l.end();) {
        int i=*it;
        if(total==n||(cnt==n-1-s[now].size())) break;
		++idx;
        if(vis[i]) {
            ++it;
            continue;
        }
        if(s[now].find(i)==s[now].end()) {
            ans--;
            it=l.erase(it);
            del+=dfs(i,1);
			++del;
            ++cnt;
        } else
            ++it;
    }
	return del;

}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> n >> m;
    for(int i=1;i<n;++i) {
        l.push_back(i);
    }
    for(int i=0;i<m;++i) {
        int u, v;
        cin >> u >> v;
        u--; v--;
        s[u].insert(v);
        s[v].insert(u);
    }
    ans=n-1;
    total=0;
    for(int i=0;i<n;++i)
        if(vis[i]==0) dfs(i,0);

    cout << ans << endl;

}


#include<bits/stdc++.h>
#define N 100005

using namespace std;

int n, m;
set<int> s[N];
int vis[N];
int done[N];
int ans;
int total;

void dfs(int now) {
    vis[now]=1;
    ++total;
    int cnt=1;
    for(int i=0;i<n;++i) {
        if(total==n||(now!=0&&cnt==s[now].size())) break;
        if(vis[i]) continue;
        if(s[now].find(i)==s[now].end()) {
            ans--;
            dfs(i);
            ++cnt;
        }
    }
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> n >> m;
    for(int i=0;i<m;++i) {
        int u, v;
        cin >> u >> v;
        u--; v--;
        s[u].insert(v);
        s[v].insert(u);
    }
    ans=n-1;
    total=0;
    for(int i=0;i<n;++i)
        if(vis[i]==0) dfs(i);

    cout << ans << endl;

}


#include<bits/stdc++.h>
#define N 100005

using namespace std;

int n, m;
set<int> s[N];
list<int> l;
int vis[N];
int ans;
int total;

int dfs(int now, int cnt) {
    vis[now]=1;
    ++total;
	int del=0;
	int idx=0;
	int remain=l.size();
    for(auto it=l.begin();idx+del<remain&&it!=l.end();) {
        int i=*it;
        if(total==n||(cnt==n-1-s[now].size())) break;
		++idx;
        if(vis[i]) {
            ++it;
            continue;
        }
        if(s[now].find(i)==s[now].end()) {
            ans--;
            it=l.erase(it);
            del+=dfs(i,1);
			++del;
            ++cnt;
        } else
            ++it;
    }
	return del;

}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> n >> m;
    for(int i=1;i<n;++i) {
        l.push_back(i);
    }
    for(int i=0;i<m;++i) {
        int u, v;
        cin >> u >> v;
        u--; v--;
        s[u].insert(v);
        s[v].insert(u);
    }
    ans=n-1;
    total=0;
    for(int i=0;i<n;++i)
        if(vis[i]==0) dfs(i,0);

    cout << ans << endl;

}


#include<bits/stdc++.h>
#define N 100005

using namespace std;

int n, m;
set<int> s[N];
list<int> l;
int vis[N];
int ans;
int total;

void dfs(int now, int cnt) {
    vis[now]=1;
    ++total;
    for(auto it=l.begin();it!=l.end();) {
        int i=*it;
        if(total==n||(cnt==n-1-s[now].size())) break;
        if(vis[i]) {
            ++it;
            continue;
        }
        if(s[now].find(i)==s[now].end()) {
            ans--;
            it=l.erase(it);
            dfs(i,1);
            ++cnt;
        } else
            ++it;
    }
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> n >> m;
    for(int i=1;i<n;++i) {
        l.push_back(i);
    }
    for(int i=0;i<m;++i) {
        int u, v;
        cin >> u >> v;
        u--; v--;
        s[u].insert(v);
        s[v].insert(u);
    }
    ans=n-1;
    total=0;
    for(int i=0;i<n;++i)
        if(vis[i]==0) dfs(i,0);

    cout << ans << endl;

}


#include<bits/stdc++.h>
#define N 100005

using namespace std;

int n, m;
set<int> s[N];
int vis[N];
int ans;
int total;

void dfs(int now) {
    vis[now]=1;
    ++total;
    int cnt=0;
    for(int i=0;i<n;++i) {
        if(total==n) break;
        if(vis[i]) continue;
        if(s[now].find(i)==s[now].end()) {
            ans--;
            dfs(i);
        }
    }
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> n >> m;
    for(int i=0;i<m;++i) {
        int u, v;
        cin >> u >> v;
        u--; v--;
        s[u].insert(v);
        s[v].insert(u);
    }
    ans=n-1;
    total=0;
    for(int i=0;i<n;++i)
        if(vis[i]==0) dfs(i);

    cout << ans << endl;

}


#include<bits/stdc++.h>
#define N 100005

using namespace std;

int n, m;
set<int> s[N];
int vis[N];
int ans;

void dfs(int now) {
    vis[now]=1;
    int cnt=0;
    for(int i=0;i<n;++i) {
        if(vis[i]) continue;
        if(s[now].find(i)==s[now].end()) {
            ans--;
            dfs(i);
        }
    }
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> n >> m;
    for(int i=0;i<m;++i) {
        int u, v;
        cin >> u >> v;
        u--; v--;
        s[u].insert(v);
        s[v].insert(u);
    }
    ans=n-1;
    for(int i=0;i<n;++i)
        if(vis[i]==0) dfs(i);

    cout << ans << endl;

}


#include<bits/stdc++.h>
#define N 100005

using namespace std;

int n, m;
set<int> s[N];
int vis[N];
int done[N];
int ans;
int total;

void dfs(int now, int cnt) {
    vis[now]=1;
    ++total;
    for(int i=0;i<n;++i) {
        if(total==n||(now!=0&&cnt==s[now].size())) break;
        if(vis[i]) continue;
        if(s[now].find(i)==s[now].end()) {
            ans--;
            dfs(i,1);
            ++cnt;
        }
    }
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> n >> m;
    for(int i=0;i<m;++i) {
        int u, v;
        cin >> u >> v;
        u--; v--;
        s[u].insert(v);
        s[v].insert(u);
    }
    ans=n-1;
    total=0;
    for(int i=0;i<n;++i)
        if(vis[i]==0) dfs(i,0);

    cout << ans << endl;

}


#include<bits/stdc++.h>
#define N 100005

using namespace std;

int n, m;
set<int> s[N];
list<int> l;
int vis[N];
int ans;

void dfs(int now) {
    vis[now]=1;
    vector<int> v;
    for(auto it=l.begin();it!=l.end();) {
        int i=*it;
        if(s[now].count(i)==0) {
            if(i!=now) {
                ans--;
                v.push_back(i);
            }
            it=l.erase(it);
        } else
            ++it;
    }

    for(auto it:v)
        dfs(it);
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> n >> m;
    memset(vis,0,sizeof(vis));
    for(int i=1;i<n;++i) {
        l.push_back(i);
    }
    for(int i=0;i<m;++i) {
        int u, v;
        cin >> u >> v;
        u--; v--;
        s[u].insert(v);
        s[v].insert(u);
    }
    ans=n-1;
    for(int i=0;i<n;++i)
        if(vis[i]==0) dfs(i);

    cout << ans << endl;
}


#include<bits/stdc++.h>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;
using namespace std;
///Welcome to Nasif's Code
#define bug printf("bug\n");
#define bug2(var) cout<<#var<<" "<<var<<endl;
#define co(q) cout<<q<<endl;
#define all(q) (q).begin(),(q).end()
#define pi acos(-1)
#define inf 1000000000000000LL
#define FastRead    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define MODADD(ADD_X,ADD_Y)  (ADD_X+ADD_Y)%MOD
#define MODSUB(SUB_X,SUB_Y)  ((SUB_X-SUB_Y)+MOD)%MOD
#define MODMUL(MUL_X,MUL_Y)  (MUL_X*MUL_Y)%MOD
#define LCM(LCM_X,LCM_Y) (LCM_X/__gcd(LCM_X,LCM_Y))*LCM_Y
template <typename T> using ordered_set = tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;
typedef long long int ll;
typedef unsigned long long int ull;
const int MOD = (int)1e9+7;
const int MAX = 1e6;
int dx[]= {1,0,-1,0,1,-1,1,-1};
int dy[]= {0,1,0,-1,1,-1,-1,1};
int rem[MAX],sp[MAX];
vector<int >adj[MAX];
bool cmp(pair<int,int> &l,pair<int,int> &r)
{
    if(l.first<r.first)
        return 1;
    if(l.first>r.first)
        return 0;
    if(l.second<r.second)
        return 1;
    return 0;
}
int parent[MAX+50];
int root(int child)
{
    while(parent[child]!=child)
    {
        parent[child]=parent[parent[child]];
        child=parent[child];
    }
    return child;
}
void node_union(int x,int y)
{
    int a=root(x);
    int b=root(y);
    parent[min(a,b)]=parent[max(a,b)];
}
int main()
{
    FastRead
    //freopen("output.txt", "w", stdout);
    int n,m;
    cin>>n>>m;
    for(int i=1; i<=n; i++)
        parent[i]=i;
    for(int i=0; i<m; i++)
    {
        int u,v;
        cin>>u>>v;
        if(u>v)
            swap(u,v);
        adj[u].push_back(v);
        adj[v].push_back(u);
    }
    set<int>st,s;
    stack<int>order;
    for(int i=1; i<=n; i++)
    {
        st.insert(i);
        order.push(i);
    }
    while(!order.empty())
    {
        int i=order.top();
        order.pop();
        map<int,int>mp;
        for(auto it:adj[i])
        {
            mp[it]=1;
        }
        vector<int>v;
        for(auto it:st)
        {
            if(!mp[it])
            {
                node_union(i,it);
                v.push_back(it);
            }
        }
        for(auto it:v)
        {
            order.push(it);
            st.erase(it);
        }
        if(st.empty())
            break;
    }

    for(int i=1; i<=n; i++)
    {
        s.insert(parent[i]);
    }
    cout<<s.size()-1<<endl;

    return 0;
}


#include<bits/stdc++.h>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;
using namespace std;
///Welcome to Nasif's Code
#define bug printf("bug\n");
#define bug2(var) cout<<#var<<" "<<var<<endl;
#define co(q) cout<<q<<endl;
#define all(q) (q).begin(),(q).end()
#define pi acos(-1)
#define inf 1000000000000000LL
#define FastRead    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define MODADD(ADD_X,ADD_Y)  (ADD_X+ADD_Y)%MOD
#define MODSUB(SUB_X,SUB_Y)  ((SUB_X-SUB_Y)+MOD)%MOD
#define MODMUL(MUL_X,MUL_Y)  (MUL_X*MUL_Y)%MOD
#define LCM(LCM_X,LCM_Y) (LCM_X/__gcd(LCM_X,LCM_Y))*LCM_Y
template <typename T> using ordered_set = tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;
typedef long long int ll;
typedef unsigned long long int ull;
const int MOD = (int)1e9+7;
const int MAX = 1e6;
int dx[]= {1,0,-1,0,1,-1,1,-1};
int dy[]= {0,1,0,-1,1,-1,-1,1};
int rem[MAX],sp[MAX];
vector<int >adj[MAX];
bool cmp(pair<int,int> &l,pair<int,int> &r)
{
    if(l.first<r.first)
        return 1;
    if(l.first>r.first)
        return 0;
    if(l.second<r.second)
        return 1;
    return 0;
}
int parent[MAX+50];
int root(int child)
{
    while(parent[child]!=child)
    {
        parent[child]=parent[parent[child]];
        child=parent[child];
    }
    return child;
}
void node_union(int x,int y)
{
    int a=root(x);
    int b=root(y);
    parent[max(a,b)]=parent[min(a,b)];
}
int main()
{
    FastRead
    //freopen("output.txt", "w", stdout);
    int n,m;
    cin>>n>>m;
    for(int i=1; i<=n; i++)
        parent[i]=i;
    for(int i=0; i<m; i++)
    {
        int u,v;
        cin>>u>>v;
        adj[u].push_back(v);
    }
    set<int>st,s;
    for(int i=1; i<=n; i++)
        st.insert(i);
    for(int i=1; i<=n; i++)
    {
        map<int,int>mp;
        for(auto it:adj[i])
        {
            mp[it]=1;
        }
        vector<int>v;
        for(auto it:st)
        {
            if(!mp[it])
            {
                node_union(i,it);
                v.push_back(it);
            }
        }
        for(auto it:v)
        {
            st.erase(it);
        }
    }

    for(int i=1; i<=n; i++){
        s.insert(parent[i]);

    }
    cout<<s.size()-1<<endl;

    return 0;
}