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>
#define fi first
#define se second
#define rep(i,n) for(int i = 0; i < (n); ++i)
#define rrep(i,n) for(int i = 1; i <= (n); ++i)
#define drep(i,n) for(int i = (n)-1; i >= 0; --i)
#define srep(i,s,t) for (int i = s; i < t; ++i)
#define rng(a) a.begin(),a.end()
#define rrng(a) a.rbegin(),a.rend()
#define maxs(x,y) (x = max(x,y))
#define mins(x,y) (x = min(x,y))
#define limit(x,l,r) max(l,min(x,r))
#define lims(x,l,r) (x = max(l,min(x,r)))
#define isin(x,l,r) ((l) <= (x) && (x) < (r))
#define pb push_back
#define eb emplace_back
#define sz(x) (int)(x).size()
#define pcnt __builtin_popcountll
#define uni(x) x.erase(unique(rng(x)),x.end())
#define show(x) cout<<#x<<" = "<<x<<endl;
#define PQ(T) priority_queue<T,v(T),greater<T> >
#define bn(x) ((1<<x)-1)
#define dup(x,y) (((x)+(y)-1)/(y))
#define newline puts("")
#define v(T) vector<T>
#define vv(T) v(v(T))
using namespace std;
typedef long long int ll;
typedef unsigned uint;
typedef unsigned long long ull;
typedef pair<int,int> P;
typedef tuple<int,int,int> T;
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef vector<ll> vl;
typedef vector<P> vp;
typedef vector<T> vt;

struct UnionFind {
  vector< ll > data;

 
  UnionFind(int sz) {
    data.assign(sz, -1);
  }
  int root(int x) {
        if (data[x] < 0) return x;
        else return data[x] = root(data[x]);
  }
  bool same(ll x, ll y) {
    return root(x) == root(y);
  }
  bool unite(int x, int y, char c) {
    x = find(x), y = find(y);
    if(x == y) return (false);
    if(data[x] > data[y]) swap(x, y);
    data[x] += data[y];
    data[y] = x;
    return (true);
  }
 
  int find(int k) {
    if(data[k] < 0) return (k);
    return (data[k] = find(data[k]));
  }
 
  int size(int k) {
    return (-data[find(k)]);
  }
};
int h,w;
int main() {
  
  cin >> h >> w;
  vector<string> G(h);
  UnionFind tree(h*w);
  rep(i,h)cin >> G[i];
  auto P = [](int i,int j){
    return(i*w+j);
  };
  for(ll i=0;i<h;i++){
    for(ll j=0;j<w;j++){
      //cout<<P(i,j)<<endl;
      if(i+1<h)if(G[i+1][j] != G[i][j]) tree.unite(P(i,j),P(i+1,j),G[i+1][j]);
      if(i-1>=0)if(G[i-1][j] != G[i][j]) tree.unite(P(i,j),P(i-1,j),G[i-1][j]);
      if(j-1>=0)if(G[i][j-1] != G[i][j]) tree.unite(P(i,j),P(i,j+-1),G[i][j-1]);
      if(j+1<w)if(G[i][j+1] != G[i][j]) tree.unite(P(i,j),P(i,j+1),G[i][j+1]);
    }
  }
  ll ans = 0;
  vector< ll > color(h*w);
  rep(i,h){
    rep(j,w)
    if(G[i][j]=='#')color[tree.root(P(i,j))]++;
  }
  rep(i,h*w){
    // show(tree.data[i]);
    // show(color[i]);
    if(tree.data[i]<0){
      ll b = color[i];
      ll w = -tree.data[i]-b;
      ans+=b*w;;
    }
  }
  cout<<ans<<endl;
  return 0;
}