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: //
  // Source code recreated from a .class file by IntelliJ IDEA
  // (powered by Fernflower decompiler)
  //
  
  import java.io.BufferedWriter;
  import java.io.DataInputStream;
  import java.io.FileInputStream;
  import java.io.IOException;
  import java.io.OutputStreamWriter;
  import java.util.*;
  
  public class CFF {
      static CFF.Reader sc = new CFF.Reader();
      static BufferedWriter bw;
      static int team1;
      static int team2;
      static int minkicks;
  
      public CFF() {
      }
  
      public static void main(String[] args) throws IOException {
        //  Scanner sc=new Scanner(System.in);
          List<int[]> list=new ArrayList<>();
          for(int i=0;i<16;i++){
              int c=0;
              int cop=i;
              int[] ar=new int[4];
              while (cop!=0){
                  if(cop%2!=0){
                      ar[c]=1;
                  }
                  cop/=2;
                  c++;
              }
              list.add(ar);
          }
  
  
         int n=inputInt();
         int m=inputInt();
         int[][] boxes=new int[n][m];
         for(int i=0;i<n;i++){
             for(int j=0;j<m;j++){
                 int num=inputInt();
                 boxes[i][j]=num;
             }
         }
         boolean[][] visited=new boolean[n][m];
         List<Integer> ans=new ArrayList<>();
         for(int i=0;i<n;i++){
             for(int j=0;j<m;j++){
                 if(!visited[i][j]){
                     Sum sum=new Sum();
                     dfs(boxes,i,j,visited,n,m,list,sum);
                     ans.add(sum.sum);
                   /*  for(int p=0;p<n;p++){
                         System.out.println(Arrays.toString(visited[p]));
                     }
                     System.out.println("-----------------------------------------------------------");*/
                 }
             }
         }
         Collections.sort(ans);
         for (int i=ans.size()-1;i>=0;i--){
             print(ans.get(i)+" ");
         }
  
  
  
  
  
          bw.flush();
          bw.close();
      }
  
      public static int checker(int a) {
          if (a % 2 == 0) {
              return 1;
          } else {
              byte b;
              do {
                  b = 2;
              } while(a + b != (a ^ b));
  
              return b;
          }
      }
  
      public static boolean checkPrime(int n) {
          if (n != 0 && n != 1) {
              for(int j = 2; j * j <= n; ++j) {
                  if (n % j == 0) {
                      return false;
                  }
              }
  
              return true;
          } else {
              return false;
          }
      }
  
      public static boolean correct(int i,int j,int n,int m){
          if(i>=0&&i<n&&j>=0&&j<m){
              return true;
          }
          return false;
      }
      public static class Sum{
          int sum;
  
      }
  
      public static void dfs(int[][] boxes,int i,int j,boolean[][] visited,int n,int m,List<int[]> list,Sum sum){
          visited[i][j]=true;
          sum.sum+=1;
          int number=boxes[i][j];
          int[] binary=list.get(number);
          for(int p=3;p>=0;p--){
              if(p==3 && binary[p]==0){
                  if(correct(i-1,j,n,m) && !visited[i-1][j]) dfs(boxes,i-1,j,visited,n,m,list,sum);
              }else if(p==2&&binary[p]==0){
                  if(correct(i,j+1,n,m) && !visited[i][j+1]) dfs(boxes,i,j+1,visited,n,m,list,sum);
              }else if(p==1&&binary[p]==0){
                  if(correct(i+1,j,n,m) && !visited[i+1][j]) dfs(boxes,i+1,j,visited,n,m,list,sum);
              }else if(p==0&&binary[p]==0){
                  if(correct(i,j-1,n,m) && !visited[i][j-1]) dfs(boxes,i,j-1,visited,n,m,list,sum);
              }
          }
      }
  
      public static int inputInt() throws IOException {
          return sc.nextInt();
      }
  
      public static long inputLong() throws IOException {
          return sc.nextLong();
      }
  
      public static double inputDouble() throws IOException {
          return sc.nextDouble();
      }
  
      public static String inputString() throws IOException {
          return sc.readLine();
      }
  
      public static void print(String a) throws IOException {
          bw.write(a);
      }
  
      public static void printSp(String a) throws IOException {
          bw.write(a + " ");
      }
  
      public static void println(String a) throws IOException {
          bw.write(a + "\n");
      }
  
      public static long getAns(int[] ar, int c, long[][] dp, int i, int sign) {
          if (i < 0) {
              return 1L;
          } else if (c <= 0) {
              return 1L;
          } else {
              dp[i][c] = Math.max(dp[i][c], Math.max((long)ar[i] * getAns(ar, c - 1, dp, i - 1, sign), getAns(ar, c, dp, i - 1, 1)));
              return dp[i][c];
          }
      }
  
      public static long power(long a, long b, long c) {
          long ans;
          for(ans = 1L; b != 0L; b /= 2L) {
              if (b % 2L == 1L) {
                  ans *= a;
                  ans %= c;
              }
  
              a *= a;
              a %= c;
          }
  
          return ans;
      }
  
      public static long power1(long a, long b, long c) {
          long ans;
          for(ans = 1L; b != 0L; b /= 2L) {
              if (b % 2L == 1L) {
                  ans = multiply(ans, a, c);
              }
  
              a = multiply(a, a, c);
          }
  
          return ans;
      }
  
      public static long multiply(long a, long b, long c) {
          long res = 0L;
  
          for(a %= c; b > 0L; b /= 2L) {
              if (b % 2L == 1L) {
                  res = (res + a) % c;
              }
  
              a = (a + a) % c;
          }
  
          return res % c;
      }
  
      public static long totient(long n) {
          long result = n;
  
          for(long i = 2L; i * i <= n; ++i) {
              if (n % i == 0L) {
                  while(n % i == 0L) {
                      n /= i;
                  }
  
                  result -= result / i;
              }
          }
  
          if (n > 1L) {
              result -= result / n;
          }
  
          return result;
      }
  
      public static long gcd(long a, long b) {
          return b == 0L ? a : gcd(b, a % b);
      }
  
      public static boolean[] primes(int n) {
          boolean[] p = new boolean[n + 1];
          p[0] = false;
          p[1] = false;
  
          int i;
          for(i = 2; i <= n; ++i) {
              p[i] = true;
          }
  
          for(i = 2; i * i <= n; ++i) {
              if (p[i]) {
                  for(int j = i * i; j <= n; j += i) {
                      p[j] = false;
                  }
              }
          }
  
          return p;
      }
  
      public String LargestEven(String S) {
          int[] count = new int[10];
  
          int num;
          for(num = 0; num < S.length(); ++num) {
              ++count[S.charAt(num) - 48];
          }
  
          num = -1;
  
          for(int i = 0; i <= 8; i += 2) {
              if (count[i] > 0) {
                  num = i;
                  break;
              }
          }
  
          StringBuilder ans = new StringBuilder();
  
          for(int i = 9; i >= 0; --i) {
              int j;
              if (i != num) {
                  for(j = 1; j <= count[i]; ++j) {
                      ans.append(i);
                  }
              } else {
                  for(j = 1; j <= count[num] - 1; ++j) {
                      ans.append(num);
                  }
              }
          }
  
          if (num != -1 && count[num] > 0) {
              ans.append(num);
          }
  
          return ans.toString();
      }
  
      static {
          bw = new BufferedWriter(new OutputStreamWriter(System.out));
          team1 = 0;
          team2 = 0;
          minkicks = 10;
      }
  
      public static class Score {
          int l;
          String s;
  
          public Score(int l, String s) {
              this.l = l;
              this.s = s;
          }
      }
  
      public static class Ath {
          int r1;
          int r2;
          int r3;
          int r4;
          int r5;
          int index;
  
          public Ath(int r1, int r2, int r3, int r4, int r5, int index) {
              this.r1 = r1;
              this.r2 = r2;
              this.r3 = r3;
              this.r4 = r4;
              this.r5 = r5;
              this.index = index;
          }
      }
  
      static class Reader {
          private final int BUFFER_SIZE = 65536;
          private DataInputStream din;
          private byte[] buffer;
          private int bufferPointer;
          private int bytesRead;
  
          public Reader() {
              this.din = new DataInputStream(System.in);
              this.buffer = new byte[65536];
              this.bufferPointer = this.bytesRead = 0;
          }
  
          public Reader(String file_name) throws IOException {
              this.din = new DataInputStream(new FileInputStream(file_name));
              this.buffer = new byte[65536];
              this.bufferPointer = this.bytesRead = 0;
          }
  
          public String readLine() throws IOException {
              byte[] buf = new byte[64];
  
              int cnt;
              byte c;
              for(cnt = 0; (c = this.read()) != -1 && c != 10; buf[cnt++] = (byte)c) {
              }
  
              return new String(buf, 0, cnt);
          }
  
          public int nextInt() throws IOException {
              int ret = 0;
  
              byte c;
              for(c = this.read(); c <= 32; c = this.read()) {
              }
  
              boolean neg = c == 45;
              if (neg) {
                  c = this.read();
              }
  
              do {
                  ret = ret * 10 + c - 48;
              } while((c = this.read()) >= 48 && c <= 57);
  
              return neg ? -ret : ret;
          }
  
          public long nextLong() throws IOException {
              long ret = 0L;
  
              byte c;
              for(c = this.read(); c <= 32; c = this.read()) {
              }
  
              boolean neg = c == 45;
              if (neg) {
                  c = this.read();
              }
  
              do {
                  ret = ret * 10L + (long)c - 48L;
              } while((c = this.read()) >= 48 && c <= 57);
  
              return neg ? -ret : ret;
          }
  
          public double nextDouble() throws IOException {
              double ret = 0.0D;
              double div = 1.0D;
  
              byte c;
              for(c = this.read(); c <= 32; c = this.read()) {
              }
  
              boolean neg = c == 45;
              if (neg) {
                  c = this.read();
              }
  
              do {
                  ret = ret * 10.0D + (double)c - 48.0D;
              } while((c = this.read()) >= 48 && c <= 57);
  
              if (c == 46) {
                  while((c = this.read()) >= 48 && c <= 57) {
                      ret += (double)(c - 48) / (div *= 10.0D);
                  }
              }
  
              return neg ? -ret : ret;
          }
  
          private void fillBuffer() throws IOException {
              this.bytesRead = this.din.read(this.buffer, this.bufferPointer = 0, 65536);
              if (this.bytesRead == -1) {
                  this.buffer[0] = -1;
              }
  
          }
  
          private byte read() throws IOException {
              if (this.bufferPointer == this.bytesRead) {
                  this.fillBuffer();
              }
  
              return this.buffer[this.bufferPointer++];
          }
  
          public void close() throws IOException {
              if (this.din != null) {
                  this.din.close();
              }
          }
      }
  }
  