Problem: There is a grid with H rows and W columns, where each square is painted black or white.

You are given H strings S_1, S_2, ..., S_H, each of length W. If the square at the i-th row from the top and the j-th column from the left is painted black, the j-th character in the string S_i is `#`; if that square is painted white, the j-th character in the string S_i is `.`.

Find the number of pairs of a black square c_1 and a white square c_2 that satisfy the following condition:

* There is a path from the square c_1 to the square c_2 where we repeatedly move to a vertically or horizontally adjacent square through an alternating sequence of black and white squares: black, white, black, white...

Constraints

* 1 \leq H, W \leq 400
* |S_i| = W (1 \leq i \leq H)
* For each i (1 \leq i \leq H), the string S_i consists of characters `#` and `.`.

Input

Input is given from Standard Input in the following format:


H W
S_1
S_2
:
S_H


Output

Print the answer.

Examples

Input

3 3
.#.
..#
#..


Output

10


Input

3 3
.#.
..#
..


Output

10


Input

2 4
....
....


Output

0


Input

4 3


...


Output

6

Solution (in JAVA):

Solution:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
import java.util.stream.IntStream;

public class Main {
    public static void main(final String[] args) {
        final FastScanner scanner = new FastScanner(System.in);
        final int h = scanner.nextInt();
        final int w = scanner.nextInt();

        final boolean[][] table = new boolean[h][w];
        final List<Integer> blacks = new ArrayList<>();
        final List<Integer> whites = new ArrayList<>();
        for (int i = 0; i < h; i++) {
            final String s = scanner.next();
            for (int j = 0; j < w; j++) {
                if (s.charAt(j) == '#') {
                    table[i][j] = true;
                    blacks.add(flatten(i, j, w));
                } else {
                    whites.add(flatten(i, j, w));
                }
            }
        }

        final UnionFindTree tree = new UnionFindTree(h * w - 1);
        for (int i = 0; i < h; i++) {
            for (int j = 0; j < w; j++) {
                if (i > 0 && table[i][j] != table[i - 1][j]) {
                    tree.unit(flatten(i, j, w), flatten(i - 1, j, w));
                }
                if (i < h - 1 && table[i][j] != table[i + 1][j]) {
                    tree.unit(flatten(i, j, w), flatten(i + 1, j, w));
                }
                if (j > 0 && table[i][j] != table[i][j - 1]) {
                    tree.unit(flatten(i, j, w), flatten(i, j - 1, w));
                }
                if (j < w - 1 && table[i][j] != table[i][j + 1]) {
                    tree.unit(flatten(i, j, w), flatten(i, j + 1, w));
                }
            }
        }

        final long[] count = new long[h * w];
        for (final int black : blacks) {
            count[tree.getRoot(black)]++;
        }

        final long answer = whites.stream()
                .mapToLong(i -> count[tree.getRoot(i)])
                .sum();
        System.out.println(answer);
    }

    private static int flatten(final int i, final int j, final int w) {
        return i * w + j;
    }

    private static class UnionFindTree {
        private final Integer[] nodes;
        private final List<Integer> indices = new ArrayList<>();

        UnionFindTree(final int numOfNodes) {
            this.nodes = init(numOfNodes);
        }

        private Integer[] init(final int numOfNodes) {
            return IntStream.rangeClosed(0, numOfNodes)
                    .boxed()
                    .toArray(Integer[]::new);
        }

        int getRoot(final int nodeNumber) {
            final int rootNode = nodes[nodeNumber];
            if (rootNode == nodeNumber) {
                for (final Integer index : indices) {
                    nodes[index] = rootNode;
                }
                indices.clear();
                return nodeNumber;
            }

            indices.add(nodeNumber);
            return getRoot(rootNode);
        }

        void unit(final int nodeA, final int nodeB) {
            final int rootA = getRoot(nodeA);
            final int rootB = getRoot(nodeB);

            if (rootA == rootB) {
                return;
            }

            nodes[Math.max(rootA, rootB)] = Math.min(rootA, rootB);
        }
    }

    private static class FastScanner {
        private final BufferedReader reader;
        private StringTokenizer tokenizer;

        FastScanner(final InputStream in) {
            reader = new BufferedReader(new InputStreamReader(in));
            tokenizer = null;
        }

        String next() {
            if (tokenizer == null || !tokenizer.hasMoreTokens()) {
                try {
                    tokenizer = new StringTokenizer(reader.readLine());
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            return tokenizer.nextToken();
        }

        int nextInt() {
            return Integer.parseInt(next());
        }

    }
}