#include <iostream>
#include <fstream>
#include <string>
#include <string.h>
#include <sstream>
#include <algorithm>
#include <map>
#include <vector>
#include <stack>
#include <utility>
#include <set>
#include <numeric>  
#include <cmath>
#include <queue>
#include <functional>
#include <iomanip>
#include <unordered_map>


#define pb push_back
#define eb emplace_back
#define ll long long
#define rep(i,b,e) for(int i=(b);i<(e);i++)
#define ALL(v) v.begin(),v.end()
#define read(a, b) rep(i, 0, b) { int t; cin >> t;a.pb(t); }
using namespace std;
using std::cin;


typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef vector<int> vi;
typedef vector<ll> vl;
typedef vector<vi> vii;
typedef vector<vl> vll;
typedef vector<pii> vpii;
typedef vector<pll> vpll;
typedef priority_queue<int, vector<int>, greater<int>> pqs;

ifstream in;
ofstream out;
ostringstream oss;
std::streambuf *coutbuf;


inline int mul(int a, int b, int md) {
#if defined(_WIN32)
	return (int)((long long)a * b % md);
#else
	unsigned long long x = (long long)a * b;
	unsigned xh = (unsigned)(x >> 32), xl = (unsigned)x, d, m;
	asm(
		"divl %4; \n\t"
		: "=a" (d), "=d" (m)
		: "d" (xh), "a" (xl), "r" (md)
	);
	return m;
#endif
}

inline int power(int a, long long b,int md) {
	int res = 1;
	while (b > 0) {
		if (b & 1) {
			res = mul(res, a, md);
		}
		a = mul(a, a, md);
		b >>= 1;
	}
	return res;
}

inline int inv(int a, int md) {
	a %= md;
	if (a < 0) a += md;
	int b = md, u = 0, v = 1;
	while (a) {
		int t = b / a;
		b -= t * a; swap(a, b);
		u -= t * v; swap(u, v);
	}
	//assert(b == 1);
	if (u < 0) u += md;
	return u;
}



ll mod_pow(ll x, ll n, ll mod) {
	ll res = 1;
	while (n > 0) {
		if (n & 1) {
			res = res * x;
			res %= mod;
		}
		x = (x*x) % mod;
		n >>= 1;
	}
	return res;
}

ll gcd(ll a, ll b) {
	while (b > 0) {
		int r = a % b;
		a = b;
		b = r;
	}
	return a;
}

ll stein_gcd(ll a, ll b) {
	unsigned c = 0;
	while (1)
	{
		if (a == 0)
			return b << c;
		else if (b == 0)
			return a << c;
		if (!(a & 1) && !(b & 1))
		{
			a >>= 1; b >>= 1; ++c;
		}
		else if (!(a & 1) && (b & 1))
		{
			a >>= 1;
		}
		else if ((a & 1) && !(b & 1))
		{
			b >>= 1;
		}
		else if ((a & 1) && (b & 1))
		{
			unsigned tmp = a > b ? b : a;
			a = a > b ? a - b : (b - a);
			b = tmp;
		}
	}
}

tuple<int, int, int> xgcd(int a, int b) {
	int x = 0, y = 1, px = 1, py = 0;
	while (b != 0) {
		int q = a / b;
		int tx = x;
		x = px - q * x;
		px = tx;
		int ty = y;
		y = py - q * y;
		py = ty;
		int r = a % b;
		a = b;
		b = r;
	}

	return make_tuple(a, px, py);
}

// two pointers 

int snake_find(int limit, vector<int> a) {
	int n = a.size();
	int t = 0, s = 0, sum = 0;
	int res = n + 1;
	while (1) {
		while (t < n && sum < limit) {
			sum += a[t++];
		}
		// not satisfied
		if (sum < limit) {
			break;
		}
		res = min(res, t - s + 1);
		// remove first element;
		sum -= a[s++];
	}

	return res;
}

vi id;
vi sz;
int groups;

void init(int n)
{
	groups = n;
	id = vector<int>(n, 0);
	for (int i = 0; i < n; i++)
	{
		id[i] = i;
	}
	sz = vi(n, 1);
}

int findRoot(int p)
{
	while (p != id[p])
	{
		id[p] = id[id[p]];
		p = id[p];
	}
	return p;
}

void comb(int p, int q) {
	int i = findRoot(p);
	int j = findRoot(q);
	if (i == j)
	{
		return;
	}
	if (sz[i] < sz[j])
	{
		id[i] = j;
		sz[j] += sz[i];
	}
	else
	{
		id[j] = i;
		sz[i] += sz[j];
	}
	groups--;
}









int rd() {
	int x = 0, f = 1; char c = getchar();
	while (c<'0' || c>'9') { if (c == '-')f = -1; c = getchar(); }
	while (c >= '0'&&c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
	return x * f;
}




#define code_chef
int stage = 0;
string problem = "B";
ll solve() {



	return 1;
}


















set<int> st;
int h, w;
ll hei = 0;
ll bai = 0;
void dfs(int i,int j, char color, vector<string> &vs) {
	
	if (vs[i][j] == '#') {
		bai++;
	}
	else {
		hei++;
	}
	vs[i][j] = 'a';
	vector<int> hh = { 0,0,1,-1 };
	vector<int> ss = { 1,-1,0,0 };
	for (int ix = 0; ix < 4; ix++) {
		int nx = i + hh[ix];
		int ny = j + ss[ix];
		if (nx >= 0 && nx < h&&ny >= 0 && ny < w&&vs[nx][ny]!='a'&&vs[nx][ny] != color) {
			dfs(nx, ny, vs[nx][ny], vs);
		}
	}

}

void goforit() {
	 cin >> h >> w;
	vector<string> vs;
	for (int i = 0; i < h; i++) {
		string s; cin >> s;
		vs.pb(s);
	}
	ll r = 0;
	for (int i = 0; i < h; i++) {
		for (int j = 0; j < w; j++) {
			if (vs[i][j] != 'a') {
				hei = 0;
				bai = 0;
				dfs(i,j,vs[i][j],vs);
				r += hei*bai;
			}
		}
	}
	cout << r << endl;
}




int main() {
	ios_base::sync_with_stdio(false); cin.tie(0);
#ifdef code_jam 
	if (stage == 1) {
		in.open(problem + "-small-attempt0.in"); cin.rdbuf(in.rdbuf());
		out.open(problem + "-small-attempt0.out"); cout.rdbuf(out.rdbuf());
	}
	else if (stage == 2) {
		in.open(problem + "-large.in"); cin.rdbuf(in.rdbuf());
		out.open(problem + "-large.out"); cout.rdbuf(out.rdbuf());
	}
	else {
		coutbuf = cout.rdbuf(oss.rdbuf());
	}
	int t; cin >> t;
	for (int i = 1; i <= t; i++) {
		cout << "Case #" << i << ": " << solve() << "\n";
	}
	if (stage == 0) {
		std::cout.rdbuf(coutbuf);
		cout << oss.str();
	}

#endif

	goforit();

	return 0;
}


Measured memory_bytes: 25472