description: You have received data from a Bubble bot. You know your task is to make factory facilities, but before you even start, you need to know how big the factory is and how many rooms it has. When you look at the data you see that you have the dimensions of the construction, which is in rectangle shape: N x M. 
  
  Then in the next N lines you have M numbers. These numbers represent factory tiles and they can go from 0 to 15. Each of these numbers should be looked in its binary form. Because from each number you know on which side the tile has walls. For example number 10 in it's binary form is 1010, which means that it has a wall from the North side, it doesn't have a wall from the East, it has a wall on the South side and it doesn't have a wall on the West side. So it goes North, East, South, West. 
  
  It is guaranteed that the construction always has walls on it's edges. The input will be correct. 
  
  Your task is to print the size of the rooms from biggest to smallest. 
  
  Input
  
  The first line has two numbers which are N and M, the size of the construction. Both are integers: 
  
  n (1 ≤ n ≤ 10^3)
  
  m (1 ≤ m ≤ 10^3)
  
  Next N x M numbers represent each tile of construction.
  
  Output
  
  Once you finish processing the data your output consists of one line sorted from biggest to smallest room sizes. 
  
  Example
  
  Input
  
  
  4 5
  9 14 11 12 13
  5 15 11 6 7
  5 9 14 9 14
  3 2 14 3 14
  
  
  Output
  
  
  9 4 4 2 1 
solution: import os
  import sys
  from io import BytesIO, IOBase
  import math as mt
  import itertools as it
  import operator as op
  import bisect as bs
  import heapq as hp
  from functools import reduce
  from io import BytesIO, IOBase
  import pprint
  import logging
  from logging import getLogger
  import array
  from collections import deque, defaultdict, OrderedDict, Counter, ChainMap, _chain
  maxx, localsys, mod = 1 << 60, 0, int(1e9 + 7)
  def nCr(n, r): return reduce(op.mul, range(n - r + 1, n + 1), 1) // mt.factorial(r)
  
  def ceil(a, b): return (a + b - 1) // b
  
  def lcm(a, b): return a * b // mt.gcd(a, b)
  
  
  gcdm = lambda *args: reduce(mt.gcd, args, 0)
  
  def lcm(a, b): return a * b // mt.gcd(a, b)
  
  
  lcmm = lambda *args: reduce(lcm, args, 1)
  
  logging.basicConfig(
      format="%(message)s",
      level=logging.WARNING,
  )
  logger = getLogger(__name__)
  logger.setLevel(logging.INFO)
  
  
  def debug(msg, *args):
      logger.info(f'{msg}={pprint.pformat(args)}')
  
  
  _str = str
  str = lambda x=b"": x if type(x) is bytes else _str(x).encode()
  
  BUFSIZE = 8192
  
  
  class FastIO(IOBase):
      newlines = 0
  
      def __init__(self, file):
          self._fd = file.fileno()
          self.buffer = BytesIO()
          self.writable = "x" in file.mode or "r" not in file.mode
          self.write = self.buffer.write if self.writable else None
  
      def read(self):
          while True:
              b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
              if not b:
                  break
              ptr = self.buffer.tell()
              self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr)
          self.newlines = 0
          return self.buffer.read()
  
      def readline(self):
          while self.newlines == 0:
              b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
              self.newlines = b.count(b"\n") + (not b)
              ptr = self.buffer.tell()
              self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr)
          self.newlines -= 1
          return self.buffer.readline()
  
      def flush(self):
          if self.writable:
              os.write(self._fd, self.buffer.getvalue())
              self.buffer.truncate(0), self.buffer.seek(0)
  
  
  class IOWrapper(IOBase):
      def __init__(self, file):
          self.buffer = FastIO(file)
          self.flush = self.buffer.flush
          self.writable = self.buffer.writable
          self.write = lambda s: self.buffer.write(s.encode("ascii"))
          self.read = lambda: self.buffer.read().decode("ascii")
          self.readline = lambda: self.buffer.readline().decode("ascii")
  
  
  sys.stdin, sys.stdout = IOWrapper(sys.stdin), IOWrapper(sys.stdout)
  def input(): return sys.stdin.readline().rstrip("\r\n")
  
  # end region
  
  
  def maps(): return map(int, input().split())
  
  #   THINK ABOUT THE EDGE CASES ..........
  
  #   DON'T SUBMIT UNLESS YOU ARE ABSOLUTELY SURE !!!!!
  
  
  class DisjointSetUnion:
      def __init__(self, n):
          self.n = n
          self.parent = list(range(n))
          self.size = [1] * n
          self.numsets = n
  
      def find(self, x):
          xcopy = x
          while self.parent[x] != x:
              x = self.parent[x]
          while xcopy != x:
              xcopy, self.parent[xcopy] = self.parent[xcopy], x
          return x
  
      def union(self, x, y):
          a, b = self.find(x), self.find(y)
          if a != b:
              if self.size[a] < self.size[b]:
                  a, b = b, a
  
              self.size[a] += self.size[b]  # sz.a > sz.b
              self.parent[b] = a
              self.numsets -= 1
  
      def get_size(self, x):
          return self.size[self.find(x)]
  
      def __len__(self):  # number of components
          return self.numsets
  
  
  from collections import defaultdict, Counter
  n, m = maps()
  arr = [['0' * (4 - len(bin(i)[2:])) + bin(i)[2:] for i in maps()] for _ in range(n)]
  dsu = DisjointSetUnion(n * m)
  cnt = 0
  S = 'NESW'
  for i in range(n):
      for j in range(m):
          for k in range(4):
              if arr[i][j][k] == '0':
                  if S[k] == 'N' and cnt - m >= 0:
                      dsu.union(cnt, cnt - m)
                  if S[k] == 'E':
                      dsu.union(cnt, cnt + 1)
                  if S[k] == 'S':
                      dsu.union(cnt, cnt + m)
                  if S[k] == 'W':
                      dsu.union(cnt, cnt - 1)
          cnt += 1
  
  
  d = defaultdict(int)
  ans = []
  for i in range(n * m):
      if dsu.find(i) == i:
          ans.append(dsu.get_size(i))
  
  print(*sorted(ans)[::-1], '')
  