import scala.collection.mutable

object Main extends App {
  val sc = new java.util.Scanner(System.in)
  val N, M = sc.nextInt()
  val disjointSet = DisjointSet.apply(1.to(N): _*)
  1.to(M).foreach(_ => disjointSet.union(sc.nextInt(), sc.nextInt()))
  println(disjointSet.sets.size - 1)
  
  class DisjointSet[A] {
    
    import DisjointSet.Node
    
    private[this] val parent = mutable.Map.empty[A, Node[A]]

    private[this] implicit def toNode(x: A): Node[A] = {
      assume(contains(x))
      parent(x)
    }

    def contains(x: A): Boolean = parent contains x

    def +=(x: A): Unit = {
      assume(!contains(x))
      parent(x) = new Node(x)
    }

    def union(x: A, y: A): Unit = {
      val (xRoot, yRoot) = (x.root, y.root)
      if (xRoot != yRoot) {
        if (xRoot.rank < yRoot.rank) {
          xRoot.parent = yRoot
        } else if (xRoot.rank > yRoot.rank) {
          yRoot.parent = xRoot
        } else {
          yRoot.parent = xRoot
          xRoot.rank += 1
        }
      }
    }

    def apply(x: A): A = x.root.entry

    def sets: Iterable[Iterable[A]] = parent.keys.groupBy(_.root.entry).values
  }

  object DisjointSet {

    private[DisjointSet] class Node[A](val entry: A) {

      var (parent, rank) = (this, 0)

      def root: Node[A] = {
        if (parent != this) {
          parent = parent.root
        }
        parent
      }
    }

    def empty[A] = new DisjointSet[A]

    def apply[A](elements: A*): DisjointSet[A] = {
      val d = empty[A]
      elements foreach {e => d += e}
      d
    }
  }

}
