#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef vector<ll> vll;
typedef pair<ll, ll> pll;
typedef vector<pll> vpll;
typedef string str;
static const long long INF = INT64_MAX;
static const long long MOD = (ll)1e9+7;

#define endl "\n"
#define fast_io ios_base::sync_with_stdio(false);cin.tie(NULL)
#define REP(i, n) for(ll i=0;i<n;i++)
#define SZ(v) (ll)((v).size())
#define WHOLE(v) (v).begin(), (v).end()
#define ASC(v) sort((v).begin(), (v).end())
#define DESC(v) sort((v).rbegin(), (v).rend())
#define INV(v) reverse((v).begin(), (v).end())
#define FOLDL(src, dst, lambda) partial_sum((src).begin(), (src).end(), (dst).begin(), lambda)
#define FOLDR(src, dst, lambda) INV(src);partial_sum((src).begin(), (src).end(), (dst).begin(), lambda);INV(dst)
#define CUMSUML(src, dst) FOLDL(src, dst, [](auto a, auto b) {return a+b;})
#define CUMSUMR(src, dst) FOLDR(src, dst, [](auto a, auto b) {return a+b;})
#define ACCUM(v, d0, lambda) accumulate((v).begin(), (v).end(), d0, lambda)
#define SUM(v, d0) ACCUM(v, d0, [](auto a, auto b) {return a+b;})
#define ERASE(v, i) v.erase(v.begin() + i)
#define UNIQ(v) ASC(v);v.erase(unique(v.begin(), v.end()), v.end())

template <typename T>void debug(T t) {cerr << t << endl;}
template <typename T, typename ...Args>void debug(T t, Args ...args) {cerr << t << " ";debug(args...);}
template <typename T>void out(T t) {cout << t << endl;}
template <typename T, typename ...Args>void out(T t, Args ...args) {cout << t << " ";out(args...);}

struct Edge{pll from, to;};

void solve() {
    ll H,W;
    cin >> H >> W;
    vector<vll> mp, vis(H);
    mp.resize(H);
    REP(i, H) {
        str S;
        cin >> S;
        mp[i].resize(W);
        vis[i].resize(W);
        REP(j, W) {
            mp[i][j] = S[j] == '#' ? 1 : 0;
            vis[i][j] = -1;
        }
    }
    
    vector<vector<Edge> > path(H*W);
    vll dx = {-1, 0, 1, 0};
    vll dy = {0, -1, 0, 1};
    REP(y, H) {
        REP(x, W) {
            REP(i, 4) {
                if(x+dx[i]>=0&&x+dx[i]<W&&y+dy[i]>=0&&y+dy[i]<H) {
                    ll nx = x+dx[i];
                    ll ny = y+dy[i];
                    if(mp[y][x] != mp[ny][nx]){
                        path[x+y*W].push_back({{x, y}, {nx, ny}});
                        path[nx+ny*W].push_back({{nx, ny}, {x, y}});
                    }
                }
            }
        }
    }
    ll ans = 0;
    REP(y, H) {
        REP(x, W) {
            if(vis[y][x] != -1) continue;
            queue<ll> q;
            vll nwb(2);
            q.push(y*W+x);
            vis[y][x] = 0;
            nwb[mp[y][x]]++;
            while(!q.empty()) {
                ll f = q.front();
                ll px = f % W;
                ll py = f / W;
                q.pop();
                auto routes = path[py*W+px];
                for(auto &e:routes) {
                    ll nx = e.to.first;
                    ll ny = e.to.second;
                    if(vis[ny][nx] == -1) {
                        vis[ny][nx] = 0;
                        nwb[mp[ny][nx]]++;
                        q.push(ny*W+nx);
                    }
                }
            }
            ans += nwb[0] * nwb[1];
        }
    }
    out(ans);
}

int main() {
    fast_io;
    solve();
    return 0;
}


Measured memory_bytes: 49024