#include<bits/stdc++.h>
using namespace std;
using ll = long long;
using Graph = vector<vector<int>>;
const ll mod=1000000007;
/* 4 方向への隣接頂点への移動を表すベクトル */
const int dx[4] = { 1, 0, -1, 0 };
const int dy[4] = { 0, 1, 0, -1 };
int main() {

    ////////////////////////////////////////
    /* 入力受け取り */
    ////////////////////////////////////////

    /* 縦と横の長さ */
    int H, W;
    cin >> H >> W;
    ll sy,sx,ca=0,a=0,b=0;
    /* 盤面 */
    vector<string> field(H);
    vector<vector<int> > dist(H, vector<int>(W, -1)); 
    for (int h = 0; h < H; ++h) cin >> field[h];

    /* スタート地点とゴール地点 */
    for (int h = 0; h < H; ++h) {
        for (int w = 0; w < W; ++w) {
            if (field[h][w] != '#'||dist[h][w]!=-1) {
              continue;}
            else{
                sx = w;
                sy = h;
                b++;
            }
            


    ////////////////////////////////////////
    /* 幅優先探索の初期設定 */
    ////////////////////////////////////////

    // 各セルの最短距離 (訪れていないところは -1 としておく)
    
    dist[sy][sx] = 1; // スタートを 0 に

    // 探索中に各マスはどのマスから来たのかを表す配列 (最短経路長を知るだけなら、これは不要)
    //vector<vector<int> > prev_x(height, vector<int>(width, -1));
    //vector<vector<int> > prev_y(height, vector<int>(width, -1));

    // 「一度見た頂点」のうち「まだ訪れていない頂点」を表すキュー
    queue<pair<int, int> > que; 
    que.push(make_pair(sy, sx)); // スタートを push
    //cout << sy << sx << endl;

    ////////////////////////////////////////
    /* 幅優先探索を実施 */
    ////////////////////////////////////////    

    /* キューが空になるまで */
    while (!que.empty()) {
        pair<int, int> current_pos = que.front(); // キューの先頭を見る (C++ ではこれをしても pop しない)
        int y = current_pos.first;
        int x = current_pos.second;
        que.pop(); // キューから pop を忘れずに
        //cout << y << " " << x << endl;
        // 隣接頂点を探索
        for (int direction = 0; direction < 4; ++direction) {
            int next_x = x + dx[direction];
            int next_y = y + dy[direction];
            if (next_x < 0 || next_y >= H || next_y < 0 || next_x >= W) continue; // 場外アウトならダメ
            //cout << next_y << " " << next_x << "n" << endl;
            // まだ見ていない頂点なら push
            if (dist[next_y][next_x] == -1&&field[y][x]!=field[next_y][next_x]) {
                que.push(make_pair(next_y, next_x));  if(field[next_y][next_x]!='#'){a++;}
                else{ b++;}
                dist[next_y][next_x] = 1;}
                 // (next_x, next_y) の距離も更新
                //prev_x[next_x][next_y] = x;  // どの頂点から情報が伝播して来たか、縦方向の座標をメモ
                //prev_y[next_x][next_y] = y;  // どの頂点から情報が伝播して来たか、横方向の座標をメモ
            
        }
    }

       ca+=a*b; 
       //cout << a << " " << b << " " << ca << endl;
          a=0; b=0;
      }}
    ////////////////////////////////////////
    /* 結果出力 */
    ////////////////////////////////////////    

    //int x = gx, y = gy;
    //while (x != -1 && y != -1) {
        //field[x][y] = 'o'; // 通過したことを示す

        // 前の頂点へ行く
        //int px = prev_x[x][y];
        //int py = prev_y[x][y];
        //x = px, y = py;
    //}
    //for (int h = 0; h < height; ++h) {
        //for (int w = 0; w < width; ++w) {
            //cout << std::setw(3) << field[h][w];
        //}
        cout << ca << endl;
    }



Measured memory_bytes: 4408