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

typedef long long ll;
typedef unsigned long long ull;
//typedef long double ld;

typedef map<int, int> mii;
typedef pair<int, int> pii;
typedef pair<double,double> pdd;
typedef set<int> si;
typedef set<ll> sll;
typedef vector<int> vi;
typedef vector<pair<int, int > > vii;
typedef vector<ll> vll;
typedef vector<double> vd;
typedef vector<vi> vvi;
typedef vector<vii> vvii;
typedef vector<vll> vvll;

constexpr ll MOD = 1e9+7;
constexpr int INF = 1<<30;
constexpr ll  LINF = 1LL<<60;

#define Sort(x) sort(x.begin(),x.end())
#define Reverse(x) reverse(x.begin(),x.end())
#define ABS(a,b) ((a)<(b)?(b)-(a):(a)-(b))
#define nbit(n) (1ll<<(n))

// sort(begin(x), end(x), greater<ll>());
// lower_bound(a.begin(), a.end(), val): a[i] ≥ valである最左の位置
// upper_bound(a.begin(), a.end(), val): a[i] > valである最左の位置

// Returns minimum of a and b.
// If a is less b, a is set to b.
template<typename T>
T chmin(T& a, T b) {
  if (a > b) {
    a = b;
  }
  return a;
}

// Returns maximum of a and b.
// If a is less b, a is set to b.
template<typename T>
T chmax(T& a, T b) {
  if (a < b) {
    a = b;
  }
  return a;
}

// a = (a+b)%MOD;
void addmod(ll& a, ll b) {
  a = (a+b)%MOD;
}

template <typename T>
void dumpContents(const T& v, const string& msg)
{
  cerr << "### " << msg << " ###\n";
  for (const auto& x : v) {
    cerr << x << " ";
  }
  cerr << endl;
}

struct before_main_function {
  before_main_function() {
    cin.tie(0);
    ios::sync_with_stdio(false);
    cout<<setprecision(20)<<fixed;
    #define endl "\n"
  }
} before_main_function;

// ========== end of template ==========
constexpr int H_MAX = 400;
int H, W;
char board[H_MAX+2][H_MAX+2]; // 0-indexed

vvi G(H_MAX*H_MAX); // 0-indexed

int nodeID(int h, int w) {
  assert(1<= h && h <= H);
  assert(1<= w && w <= W);

  return (h-1)*W + w - 1;
}

char getColor(int nodeID) {
  int h = nodeID/W + 1;
  int w = nodeID%W + 1;
  return board[h][w];
}

void dfs(vector<bool>& defined, int x, vi& nodes) {
  for (auto c : G[x]) {
    if (defined[c]) continue;
    defined[c] = true;
    nodes.emplace_back(c);
    dfs(defined, c, nodes);
  }
}

int main(int argc, char** argv) {
  cin >> H >> W;

  for (int i=0; i<H_MAX+2; i++) {
    for (int j=0; j<H_MAX+2; j++) {
      board[i][j] = -1; // wall
    }
  }

  for (int h=1; h<=H; h++) {
     string S;
     cin >> S;
     for (int j=0; j<W; j++) {
       char c = S[j];
       board[h][j+1] = c; //1-indexed
     }
  }

  for (int h=1; h<=H; h++) {
    for (int w=1; w<=W; w++) {
      const int c1 = nodeID(h, w);

      for (int y : {-1, 1}) {
        if (board[h+y][w] > 0 && board[h][w] != board[h+y][w]) {
	  int c2 = nodeID(h+y, w);
	  G[c1].emplace_back(c2);
	}
      }
      for (int x : {-1, 1}) {
        if (board[h][w+x] > 0 && board[h][w] != board[h][w+x]) {
	  int c2 = nodeID(h, w+x);
	  G[c1].emplace_back(c2);
	}
      }
    }
  }

  vector<bool> defined(H_MAX*H_MAX);
  ll ret = 0;
  for (int i=0; i<H*W; i++) {
    if (getColor(i) != '#') continue;

    if (defined[i]) continue;

    vi nodes{i}; // 連結
    defined[i] = true;
    dfs(defined, i, nodes);

    //cerr << "=== HOGE " << i << endl;
    ll nblack = 0;
    ll nwhite = 0;
    for (auto j : nodes) {
      int h = j/W+1;
      int w = j%W+1;
      //cerr << "("<<h<<","<<w<<")" << endl;
      if (getColor(j) == '#') {
        nblack++;
      } else {
        nwhite++;
      }
    }
    ret += nblack * nwhite;
  }

  cout << ret << endl;

  return 0;
}


Measured memory_bytes: 19956