object Main extends App {

  import scala.io.StdIn._
  val Array(h, w) = readLine.trim.split(' ').map(_.toInt)
  val state = Array.tabulate(h){_ ⇒ readLine.trim.toCharArray.map{_ == '#'}}
  val union = Array.tabulate(h){i ⇒ Array.tabulate(w){j ⇒ new UnionFindTree(state(i)(j))}}
  for (i ← 0 until h; j ← 1 until w){
    if (state(i)(j) != state(i)(j - 1)) union(i)(j).merge(union(i)(j - 1))
  }
  for (i ← 1 until h; j ← 0 until w){
    if (state(i)(j) != state(i - 1)(j)) union(i)(j).merge(union(i - 1)(j))
  }
  val searched = new UnionFindTree(true)
  println(
    (for (i ← 0 until h; j ← 0 until w) yield {
      if (searched.isSameUnion(union(i)(j))) {
        0
      }else{
        val result = union(i)(j).blackCount * union(i)(j).whiteCount
        union(i)(j).merge(searched)
        result
      }
    }).sum
  )


  class UnionFindTree(isBlack: Boolean){
    private var mBlackCount: Int = if (isBlack) 1 else 0
    private var mParent: Option[UnionFindTree] = None
    private var mSize: Int = 1
    def blackCount: Int = parent.mBlackCount
    def whiteCount: Int = parent.mSize - parent.mBlackCount
    private def parent: UnionFindTree = {
      mParent.map{_.parent} match {
        case None ⇒ this
        case c@Some(p) ⇒
          mParent = c
          p
      }
    }
    def isSameUnion(that: UnionFindTree): Boolean = {
      parent == that.parent
    }
    def merge(that: UnionFindTree): Unit = {
      if (!isSameUnion(that)){
        val p = parent
        val tp = that.parent
        if (p.mSize > tp.mSize){
          tp.mParent = Some(p)
          p.mSize += tp.mSize
          p.mBlackCount += tp.mBlackCount
        }else {
          p.mParent = Some(tp)
          tp.mSize += p.mSize
          tp.mBlackCount += p.mBlackCount
        }
      }
    }
  }
  implicit class Extension[T](value :T){
    @inline
    def let[A](@inline func: T ⇒ A): A = func(value)
    @inline
    def also(@inline func: T ⇒ Unit): T = {func(value); value}
  }
}