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 C++14 (GCC 5.4.1) (judge verdict: Accepted)

#include <bits/stdc++.h>
using namespace std;

struct Dsu {
  vector<int> fa, szb, szw;
  Dsu(int n) : fa(n), szb(n, 0), szw(n, 0) {
    iota(fa.begin(), fa.end(), 0);
  }
  int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); }
  void unite(int x, int y) {
    int a = find(x);
    int b = find(y);
    if (a != b) {
      fa[a] = b;
      szb[b] += szb[a];
      szw[b] += szw[a];
    }
  }
};

signed main() {
  ios::sync_with_stdio(false);

  int H, W;
  cin >> H >> W;

  vector<string> S(H);
  for (int i = 0; i < H; ++i) cin >> S[i];

  Dsu dsu(H * W);
  for (int i = 0; i < H * W; ++i) {
    dsu.szw[i] = S[i / W][i % W] == '.';
    dsu.szb[i] = S[i / W][i % W] == '#';
  }
  vector<int> vis(H * W);
  for (int i = 0; i < H; ++i) {
    for (int j = 0; j < W; ++j) {
      if (vis[i * W + j]) continue;
      queue<int> que;
      que.push(i * W + j);
      vis[i * W + j] = 1;
      while (que.size()) {
        int x = que.front() / W;
        int y = que.front() % W;
        que.pop();
        static const int dx[] = {0, 1, 0, -1};
        static const int dy[] = {1, 0, -1, 0};
        for (int di = 0; di < 4; ++di) {
          int nx = x + dx[di];
          int ny = y + dy[di];
          if (nx < 0 || H <= nx || ny < 0 || W <= ny) continue;
          if (vis[nx * W + ny]) continue;
          if (S[nx][ny] == S[x][y]) continue;
          que.push(nx * W + ny);
          vis[nx * W + ny] = 1;
          dsu.unite(i * W + j, nx * W + ny);
        }
      }
    }
  }

  int64_t ans = 0;
  for (int i = 0; i < H * W; ++i) {
    if (dsu.find(i) == i) {
      int szw = dsu.szw[i];
      int szb = dsu.szb[i];
      ans += 1LL * szw * szb;
    }
  }

  cout << ans << endl;

  return 0;
}