Problem:
Score : 300 points

Problem Statement

There is a grid with H rows and W columns, where each square is painted black or white.

You are given H strings S_1, S_2, ..., S_H, each of length W.
If the square at the i-th row from the top and the j-th column from the left is painted black, the j-th character in the string S_i is #; if that square is painted white, the j-th character in the string S_i is ..

Find the number of pairs of a black square c_1 and a white square c_2 that satisfy the following condition:

There is a path from the square c_1 to the square c_2 where we repeatedly move to a vertically or horizontally adjacent square through an alternating sequence of black and white squares: black, white, black, white...

Constraints

1 \leq H, W \leq 400

|S_i| = W (1 \leq i \leq H)

For each i (1 \leq i \leq H), the string S_i consists of characters # and ..

Input

Input is given from Standard Input in the following format:

H W
S_1
S_2
:
S_H

Output

Print the answer.

Sample Input 1

3 3
.#.
..#
#..

Sample Output 1

10

Some of the pairs satisfying the condition are ((1, 2), (3, 3)) and ((3, 1), (3, 2)), where (i, j) denotes the square at the i-th row from the top and the j-th column from the left.

Sample Input 2

2 4
....
....

Sample Output 2

0

Sample Input 3

4 3
###
###
...
###

Sample Output 3

6

Solution in Scala (2.11.7) (judge verdict: Accepted)

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))) {
        0L
      }else{
        val result = union(i)(j).blackCount * union(i)(j).whiteCount.toLong
        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}
  }
}