#include "bits/stdc++.h"
using namespace std;
using ll = long long;
using pii = pair<int, int>;
using pll = pair<ll, ll>;
using vi = vector<int>;
using vl = vector<ll>;
using vvi = vector<vi>;
using vvl = vector<vl>;
const ll INF = 1LL << 60;
const ll MOD = INF; // disable
template <class T>
bool chmax(T &a, const T &b) {
    return (a < b) ? (a = b, 1) : 0;
}
template <class T>
bool chmin(T &a, const T &b) {
    return (b < a) ? (a = b, 1) : 0;
}
template <class C>
void print(const C &c, std::ostream &os = std::cout) {
    std::copy(std::begin(c), std::end(c), std::ostream_iterator<typename C::value_type>(os, " "));
    os << std::endl;
}

struct UnionFind {
    vector<int> rank, parent, size;

    // +1 for 1-indexed nodes
    UnionFind(int n) : rank(n + 1, 0), parent(n + 1), size(n + 1, 1) {
        iota(parent.begin(), parent.end(), 0); // parent is itself
    }
    int root(int x) {
        if (x != parent[x]) {
            parent[x] = root(parent[x]);
        }
        return parent[x];
    }
    bool isSame(int x, int y) { return root(x) == root(y); }
    bool unite(int x, int y) { return link(root(x), root(y)); }
    bool link(int x, int y) {
        if (x == y)
            return false;
        if (rank[x] > rank[y]) {
            parent[y] = x;
            size[x] += size[y];
        } else {
            parent[x] = y;
            size[y] += size[x];
            if (rank[x] == rank[y]) {
                rank[y]++;
            }
        }
        return true;
    }
    int getSize(int x) { return size[root(x)]; }
};

struct Combination {
    vector<ll> fac, finv, inv;

    Combination(ll maxN) {
        maxN += 100; // for safety
        fac.resize(maxN + 1);
        finv.resize(maxN + 1);
        inv.resize(maxN + 1);
        fac[0] = fac[1] = 1;
        finv[0] = finv[1] = 1;
        inv[1] = 1;
        for (ll i = 2; i <= maxN; ++i) {
            fac[i] = fac[i - 1] * i % MOD;
            inv[i] = MOD - inv[MOD % i] * (MOD / i) % MOD;
            finv[i] = finv[i - 1] * inv[i] % MOD;
        }
    }
    ll operator()(ll n, ll k) {
        if (n < k)
            return 0;
        if (n < 0 || k < 0)
            return 0;
        return fac[n] * (finv[k] * finv[n - k] % MOD) % MOD;
    }
};

int main() {
    int h, w;
    cin >> h >> w;
    int n = h * w;
    vector<string> s(h);
    for (int i = 0; i < h; ++i) {
        cin >> s[i];
    }
    auto idx = [&](int y, int x) { return y * w + x; };
    const int dx[4] = {-1, 1, 0, 0};
    const int dy[4] = {0, 0, -1, 1};
    auto inside = [&](int y, int x) { return 0 <= y && y < h && 0 <= x && x < w; };
    UnionFind uf(n);
    map<int, pii> cnt; // par, bl, wh
    for (int i = 0; i < h; ++i) {
        for (int j = 0; j < w; ++j) {
            for (int k = 0; k < 4; ++k) {
                int ny = i + dy[k];
                int nx = j + dx[k];
                if (inside(ny, nx)) {
                    if (s[i][j] != s[ny][nx]) {
                        uf.unite(idx(i, j), idx(ny, nx));
                    }
                }
            }
        }
    }
    ll ret = 0;
    map<int, vector<pii>> roots;
    for (int y = 0; y < h; ++y) {
        for (int x = 0; x < w; ++x) {
            roots[uf.root(idx(y, x))].emplace_back(y, x);
        }
    }
    for (auto &p : roots) {
        ll bl = 0;
        ll wh = 0;
        for (auto &yx : p.second) {
            int y = yx.first;
            int x = yx.second;
            if (s[y][x] == '.')
                wh++;
            else
                bl++;
        }
        ret += bl * wh;
    }
    cout << ret << "\n";
    return 0;
}

Measured memory_bytes: 17408