#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> Cell;
const int MAXN = 1005;
const int directions[4][2] = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}};
int N, M;
int grid[MAXN][MAXN];
bool visited[MAXN][MAXN];
int getWall(int cell, int direction) {
return (cell >> (3 - direction)) & 1;
}
void bfs(int x, int y, vector<int>& roomSizes) {
queue<Cell> q;
q.push({x, y});
visited[x][y] = true;
int size = 0;
while (!q.empty()) {
Cell current = q.front();
q.pop();
size++;
for (int d = 0; d < 4; ++d) {
int nx = current.first + directions[d][0];
int ny = current.second + directions[d][1];
if (nx >= 0 && nx < N && ny >= 0 && ny < M && !visited[nx][ny] && !getWall(grid[current.first][current.second], d) && !getWall(grid[nx][ny], (d + 2) % 4)) {
q.push({nx, ny});
visited[nx][ny] = true;
}
}
}
}
int main() {
cin >> N >> M;
for (int i = 0; i < N; ++i) {
for (int j = 0; j < M; ++j) {
cin >> grid[i][j];
}
}
vector<int> roomSizes;
for (int i = 0; i < N; ++i) {
for (int j = 0; j < M; ++j) {
if (!visited[i][j]) {
bfs(i, j, roomSizes);
}
}
}
sort(roomSizes.rbegin(), roomSizes.rend());
for (size_t i = 0; i < roomSizes.size(); ++i) {
if (i > 0) {
cout << " ";
}
cout << roomSizes[i];
}
cout << endl;
return 0;
}