import java.io._
import java.util.StringTokenizer
import scala.util.control.Breaks.{breakable,break}

object Main extends App {
  val in = new InputReader(System.in)
  val pw = new PrintWriter(System.out)

  val H, W = in.next().toInt
  val S = new Array[String](H+1)
  for (i <- 1 to H)
    S(i) = "N" + in.next()


  //
  type Coord = (Int, Int)

  val dp = Array.ofDim[Boolean](H+1, W+1)

  def inField(p: Coord): Boolean = {
    val (x, y) = p
    1 <= x && x <= W && 1 <= y && y <= H
  }

  def mk4dir(p: Coord): List[Coord] = {
    val (x, y) = p
    List((x-1, y), (x+1, y), (x, y-1), (x, y+1)).filter(inField)
  }

  def calc(p: Coord): (Int, Int) = {
    var B = 0
    var W = 0

    val stack = new scala.collection.mutable.Stack[(Coord, Char)]
    stack.push((p, 'N'))

    while(!stack.isEmpty) {
      val (p, pre) = stack.pop()

      val (x, y) = p

      if (dp(y)(x))
        ()
      else {
        if (S(y)(x) != pre) {
          dp(y)(x) = true
          if (S(y)(x) == '#')
            B += 1
          else
            W += 1

          mk4dir(p).foreach(p => stack.push((p, S(y)(x))))
        }
      }
    }

    (B, W)
  }

  var ans = 0L
  for (y <- 1 to H)
    for(x <- 1 to W) {
      if (!dp(y)(x) && S(y)(x) == '#') {
        val (b, w) = calc((x, y))

        ans += b * w
      }
    }

  println(ans)
}


class InputReader(stream: InputStream) {
  private val reader = new BufferedReader(new InputStreamReader(stream))
  private var tokenizer: StringTokenizer = new StringTokenizer(reader.readLine())
  def next(): String = {
    while (!tokenizer.hasMoreTokens()) {
      tokenizer = new StringTokenizer(reader.readLine())
    }
    tokenizer.nextToken()
  }
}
