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: Time Limit Exceeded)

#include "bits/stdc++.h"
using namespace std;
using ll = long long;
using ld = long double;
using ull = unsigned long long;
using vi = vector<int>;
using vvi = vector<vector<int>>;
using vl = vector<ll>;
using vll = vector<vector<ll>>;
using pii = pair<int,int>;
#define FOR(i,a,b) for(ll i = (a); i < (b); i++)
#define REP(i,n) FOR(i,0,n)
#define ALL(obj) (obj).begin(), (obj).ending()
#define eb(val) emplace_back(val)
const double PI = acos(-1);
const double EPS = 1e-10;
const ll MOD = 1e9+7;
int h,w;
void cioacc(){//accelerate cin/cout
  cin.tie(0);
  ios::sync_with_stdio(false);
}
vvi dp(400,vi(400,0));
int touf(int y,int x){
  return y*w+x;
}
pii fromuf(int a){
  pii res;
  res.second = a%w;
  res.first = a/w;
  return res;
}
struct union_find{//rank,経路圧縮で高速化
  vector<int> par;//parは添字の親（または自分が根の時自身）を示す。
  vector<int> rank;//rankは木の高さ（根についてのみ実装,0-indexed）
  union_find(int n){//コンストラクタ,n個のノードを作成し、自分を親につける
    par.assign(n,0);
    rank.assign(n,0);
    for(int i = 0;i < n;++i) par[i]=i;
  }
  void init(int n){//初期化,n個のノードを作成し、自分を親につける
    par.assign(n,0);
    rank.assign(n,0);
    for(int i = 0;i < n;++i) par[i] = i;
  }
  int find(int a){//根を探す
    if(par[a]==a) return a; //親が自身を指す時、根である
    else return par[a] = find(par[a]);//根に直接つける
  }
  void unite(int a,int b){//小さい方の木の根に大きい方の根を上書きする
    int roota,rootb;
    roota = find(a),rootb = find(b);
    pii tmp1 = fromuf(roota);
    pii tmp2 = fromuf(a);
    dp[tmp1.first][tmp1.second] = dp[tmp2.first][tmp2.second];
    tmp2 = fromuf(rootb);
    dp[tmp1.first][tmp1.second] = dp[tmp2.first][tmp2.second];
    if(roota==rootb) return;
    if(rank[roota]>rank[rootb]){ //rankの高い方の根に低い方の根をつける
      par[rootb] = roota;
    }else if(rank[roota]<rank[rootb]){
      par[roota] = rootb;
    }else{ //rankが同じ時、適当な方につけ、つけられた方のrankを1増やす
      rank[roota]++;
      par[rootb] = roota;
    }
  }
};
union_find uf(160000);
int dx[]={1,-1,0,0};
int dy[]={0,0,1,-1};
bool used[400][400];
bool in_range(int y,int x){
  return 0<=y&&y<h&&0<=x&&x<w;
}
int ending;
int u,t;
int dfs(int y,int x,char c,vector<string>& s){
  if(ending) return ending;
  if(dp[y][x]){
    return ending = dp[y][x];
  }
  used[y][x]=true;
  int res = 0;
  REP(i,4){
    int nx=x+dx[i];
    int ny=y+dy[i];
    if(in_range(ny,nx)&&s[ny][nx]!=c&&!used[ny][nx]) res += dfs(ny,nx,s[ny][nx],s);
  }
  if(ending) return ending;
  if(c=='.') return res+1;
  else {
    uf.unite(touf(y,x),touf(u,t));
    return res;
  }
}
int main(){
  int ans = 0;
  cioacc();
  cin >> h >> w;
  vector<string> s(h);
  REP(i,h) cin >> s[i];
  REP(i,h) REP(j,w){
    if(s[i][j]=='#'){
      pii asp = fromuf(uf.find(touf(i,j)));
      if(dp[asp.first][asp.second]){
        ans += dp[asp.first][asp.second];
        continue;
      }
      REP(k,h)REP(l,w) used[k][l]=false;
      ending = 0;
      u = i,t = j;
      ans += dp[i][j] = dfs(i,j,'#',s);
    }
  }
  cout << ans << endl;
}