Problem:
Score : 300 points

Problem Statement

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.

Sample Input 1

3 3
.#.
..#
#..

Sample Output 1

10

Some of the pairs satisfying the condition are ((1, 2), (3, 3)) and ((3, 1), (3, 2)), where (i, j) denotes the square at the i-th row from the top and the j-th column from the left.

Sample Input 2

2 4
....
....

Sample Output 2

0

Sample Input 3

4 3
###
###
...
###

Sample Output 3

6

Solution in Java8 (OpenJDK 1.8.0) (judge verdict: Time Limit Exceeded)

import java.util.ArrayList;
import java.util.Objects;
import java.util.Scanner;

public class Main {

	private static final char BLACK = '#';
	private static final char WHITE = '.';

	private int H;
	private int W;

	public static void main(String[] args) {
		new Main().execute();
	}

	public void execute() {
		Scanner sc = new Scanner(System.in);
		H = sc.nextInt();
		W = sc.nextInt();
		sc.nextLine();
		Cell[][] board = new Cell[H][W];
		ArrayList<Cell> blacks = new ArrayList<>();
		ArrayList<Cell> whites = new ArrayList<>();
		UFCell uf = new UFCell();

		for (int i = 0; i < H; i++) {
			String line = sc.nextLine();
			for (int j = 0; j < W; j++) {
				char c = line.charAt(j);
				Cell cell;
				switch (c) {
				case BLACK:
					cell = new Cell(i, j, BLACK);
					board[i][j] = cell;
					blacks.add(cell);
					uf.add(cell);
					break;
				case WHITE:
					cell = new Cell(i, j, WHITE);
					board[i][j] = cell;
					whites.add(cell);
					uf.add(cell);
					break;
				default:
					throw new IllegalArgumentException();
				}
			}
		}
		for (int i = 0; i < H; i++) {
			for (int j = 0; j < W; j++) {
				Cell c = board[i][j];
				if (i > 0 && c.Color != board[i - 1][j].Color) {
					uf.union(c, board[i - 1][j]);
				}
				if (j > 0 && c.Color != board[i][j - 1].Color) {
					uf.union(c, board[i][j - 1]);
				}
				if (i < H - 1 && c.Color != board[i + 1][j].Color) {
					uf.union(c, board[i + 1][j]);
				}
				if (j < W - 1 && c.Color != board[i][j + 1].Color) {
					uf.union(c, board[i][j + 1]);
				}
			}
		}

		int cnt = 0;
		for (Cell b : blacks) {
			for (Cell w : whites) {
				if (uf.find(b, w)) {
					cnt++;
				}
			}
		}
		System.out.println(cnt);
		sc.close();
	}

	class Cell {
		public final int id;
		public final char Color;
		public final int x;
		public final int y;

		public Cell(int x, int y, char color) {
			this.x = x;
			this.y = y;
			this.Color = color;
			this.id = H * y + x;
		}

		@Override
		public boolean equals(Object obj) {
			// TODO Auto-generated method stub
			if (obj instanceof Cell) {
				Cell that = (Cell) obj;
				return (this.x == that.x) && (this.y == that.y);
			} else {
				return false;
			}
		}

		@Override
		public int hashCode() {
			return Objects.hash(this.x, this.y);
		}

	}

	class UFCell {
		private int parents[] = new int[H * W];

		public void add(Cell c) {
			parents[c.id] = c.id;
		}

		private int rootID(int cid) {
			if (parents[cid] == cid) {
				return cid;
			} else {
				int pid = parents[cid];
				int root = rootID(pid);
				parents[cid] = root;
				return root;
			}
		}

		public void union(Cell c1, Cell c2) {
			int r1 = rootID(c1.id);
			int r2 = rootID(c2.id);
			if (r1 == r2) {
				return;
			} else {
				parents[r1] = r2;
			}
		}

		public boolean find(Cell c1, Cell c2) {
			return rootID(c1.id) == rootID(c2.id);
		}
	}

}