Buggy python submission (verdict: Time Limit Exceeded):

def main():
    H,W = map(int, input().split())

    S = [list(input()) for _ in range(H)]
    stack = [(i,j) for i in range(H) for j in range(W) if S[i][j] == "#"]
    #flag = False
    ans = 0
    for i,j in stack:
        ans += solve(H,W,S,[(i,j)])
    """
    for p,q in stack:
        visited = [[False for _ in range(W)] for _ in range(H)]
        visited[p][q] = True
        substack = [(p,q)]
        for i,j in substack:
            for a,b in [(i-1,j), (i+1, j), (i, j-1), (i, j+1)]:
                if 0 <= a <= H-1 and 0 <= b <= W-1:
                    if S[i][j] == "#" and S[a][b] == ".":
                        ans += 1
                        new_stack.append((a,b))
                    elif S[i][j] == "." and S[a][b] == "#":
                        new_stack.append((a,b))
                    else:
                        continue
    """

    """
    if stack:
        flag = True
    while flag:
        flag = False
        new_stack = []
        #print("ssssss",stack)
        for i,j in stack:
            #print("--", stack)
            for a,b in [(i-1,j), (i+1, j), (i, j-1), (i, j+1)]:
                if 0 <= a <= H-1 and 0 <= b <= W-1:
                    if S[i][j] == "#" and S[a][b] == ".":
                        ans += 1
                        new_stack.append((a,b))
                    elif S[i][j] == "." and S[a][b] == "#":
                        new_stack.append((a,b))
                    else:
                        continue
            
        #print("nnn", new_stack)
        stack = new_stack
        if len(new_stack) != 0:
            #print("333333333333")
            stack = new_stack
            flag = True
    """

    print(ans)

def solve(H,W,S,stack):
    ret = 0
    flag = True
    checked = [[False for _ in range(W)] for _ in range(H)]
    while flag:
        flag = False
        new_stack = []
        #print("ssssss",stack)
        for i,j in stack:
            #print("--", stack)
            for a,b in [(i-1,j), (i+1, j), (i, j-1), (i, j+1)]:

                #else:
                    if 0 <= a <= H-1 and 0 <= b <= W-1:
                        if checked[a][b] == True:
                            continue
                        if S[i][j] == "#" and S[a][b] == ".":
                            ret += 1
                            new_stack.append((a,b))
                            checked[a][b] = True
                        elif S[i][j] == "." and S[a][b] == "#":
                            new_stack.append((a,b))
                            checked[a][b] = True
                        else:
                            continue
            
        #print("nnn", new_stack)
        #stack = new_stack
        if len(new_stack) != 0:
            #print("333333333333")
            stack = new_stack
            flag = True
        else:
            return ret

if __name__ == "__main__":
    main()

Fixed submission:
"""
prd_xxxさんの解答に自分向けにコメントを付けただけ
https://atcoder.jp/contests/aising2019/submissions/3986546
"""

from collections import Counter
 
H,W = map(int, input().split())
S = [input() for _ in range(H)]

class UnionFind:
    def __init__(self,N):
        self.parent = [i for i in range(N)]
        self.rank = [0] * N
        self.count = 0
    def root(self,a):
        if self.parent[a] == a:
            return a
        else:
            self.parent[a] = self.root(self.parent[a])
            return self.parent[a]
    def is_same(self,a,b):
        return self.root(a) == self.root(b)
    def unite(self,a,b):
        ra = self.root(a)
        rb = self.root(b)
        if ra == rb: return
        if self.rank[ra] < self.rank[rb]:
            self.parent[ra] = rb
        else:
            self.parent[rb] = ra
            if self.rank[ra] == self.rank[rb]: self.rank[ra] += 1
        self.count += 1

# マス目分のUnionFind木を用意
uf = UnionFind(H*W)


for i in range(H):
    for j in range(W):
        if j < W-1 and S[i][j] != S[i][j+1]:
            uf.unite(i*W+j, i*W+j+1) # 右へ移動可能のときつなぐ
        if i < H-1 and S[i][j] != S[i+1][j]:
            uf.unite(i*W+j, (i+1)*W+j) # 下へ移動可能のときつなぐ

# 親をたどって大本につなぎなおす
for i in range(H*W):
    uf.root(i)

c1 = Counter()
c2 = Counter()

for i in range(H):
    for j in range(W):
        k = i*W + j
        # uf.root(k)は連結成分の番号（ユニオンの番号）を表していて、それらにつながっている黒と白の個数を求める
        if S[i][j] == ".":
            c1[uf.root(k)] += 1
        else:
            c2[uf.root(k)] += 1

ans = 0
for k in c1.keys():
    # それぞれの連結成分について、出発地点となる黒とゴールとなる白の組み合わせの分だけ足していく
    ans += c1[k] * c2[k]

print(ans)