import Control.Arrow
import Data.Bits
import Data.List
import qualified Data.Vector as V
import qualified Data.Vector.Unboxed as VU
import qualified Data.Vector.Unboxed.Mutable as VM
import qualified Data.ByteString.Char8 as B
import System.IO.Unsafe

solve :: Int -> Int -> V.Vector B.ByteString -> Int
solve h w ss = sum $ map ((\str -> B.count '.' str * B.count '#' str) . B.pack . map (ss !!)) components
  where
    components :: [[(Int,Int)]]
    components = fst $ foldl' go ([], visited0) [0..h*w-1]
      where
        visited0 = VU.replicate (h*w) False

        go (comps, visited) i =
          if visited VU.! i
            then (comps, visited)
            else first (: comps) $ visit (x,y) visited

          where
            x = i `mod` w
            y = i `div` w
    
    (!!) :: V.Vector B.ByteString -> (Int,Int) -> Char
    vec !! (x,y) = (vec V.! y) `B.index` x

    mark :: (Int,Int) -> VU.Vector Bool -> VU.Vector Bool
    mark (x,y) vec = unsafePerformIO $ VU.thaw vec >>= \vec' -> VM.write vec' (y * w + x) True >> VU.freeze vec'
    
    visit :: (Int,Int) -> VU.Vector Bool -> ([(Int,Int)], VU.Vector Bool)
    visit = \(x,y) visited -> go [(x,y, ss !! (x,y))] [] visited
      where
        go [] acc visited = (acc,visited)
        go ((x,y,ch):ts) acc visited
          | visited VU.! (y * w + x) = go ts acc visited
          | otherwise =
              let candidate =
                    [ (x',y',ch')
                    | (ix,iy) <- [(0,1),(0,-1),(1,0),(-1,0)],
                      let x' = x+ix, let y' = y+iy,
                      0 <= x' && x' < w, 0 <= y' && y' < h,
                      not (visited VU.! (y * w + x)),
                      let ch' = ss !! (x',y'), ch /= ch'
                    ] in
              go (candidate ++ ts) ((x,y) : acc) (mark (x,y) visited)

main = do
  let readInt = fmap (second B.tail) . B.readInt

  hw <- V.unfoldrN 2 readInt <$> B.getLine
  ss <- V.replicateM (hw V.! 0) B.getLine
  print $ solve (hw V.! 0) (hw V.! 1) ss
