Problem: Dora loves adventures quite a lot. During some journey she encountered an amazing city, which is formed by n streets along the Eastern direction and m streets across the Southern direction. Naturally, this city has nm intersections. At any intersection of i-th Eastern street and j-th Southern street there is a monumental skyscraper. Dora instantly became curious and decided to explore the heights of the city buildings.

When Dora passes through the intersection of the i-th Eastern and j-th Southern street she examines those two streets. After Dora learns the heights of all the skyscrapers on those two streets she wonders: how one should reassign heights to the skyscrapers on those two streets, so that the maximum height would be as small as possible and the result of comparing the heights of any two skyscrapers on one street wouldn't change.

Formally, on every of nm intersections Dora solves an independent problem. She sees n + m - 1 skyscrapers and for each of them she knows its real height. Moreover, any two heights can be compared to get a result "greater", "smaller" or "equal". Now Dora wants to select some integer x and assign every skyscraper a height from 1 to x. When assigning heights, Dora wants to preserve the relative order of the skyscrapers in both streets. That is, the result of any comparison of heights of two skyscrapers in the current Eastern street shouldn't change and the result of any comparison of heights of two skyscrapers in current Southern street shouldn't change as well. Note that skyscrapers located on the Southern street are not compared with skyscrapers located on the Eastern street only. However, the skyscraper located at the streets intersection can be compared with both Southern and Eastern skyscrapers. For every intersection Dora wants to independently calculate the minimum possible x.

For example, if the intersection and the two streets corresponding to it look as follows:

<image>

Then it is optimal to replace the heights of the skyscrapers as follows (note that all comparisons "less", "equal", "greater" inside the Eastern street and inside the Southern street are preserved)

<image>

The largest used number is 5, hence the answer for this intersection would be 5.

Help Dora to compute the answers for each intersection.

Input

The first line contains two integers n and m (1 ≤ n, m ≤ 1000) — the number of streets going in the Eastern direction and the number of the streets going in Southern direction.

Each of the following n lines contains m integers a_{i,1}, a_{i,2}, ..., a_{i,m} (1 ≤ a_{i,j} ≤ 10^9). The integer a_{i,j}, located on j-th position in the i-th line denotes the height of the skyscraper at the intersection of the i-th Eastern street and j-th Southern direction.

Output

Print n lines containing m integers each. The integer x_{i,j}, located on j-th position inside the i-th line is an answer for the problem at the intersection of i-th Eastern street and j-th Southern street.

Examples

Input


2 3
1 2 1
2 1 2


Output


2 2 2 
2 2 2 


Input


2 2
1 2
3 4


Output


2 3 
3 2 

Note

In the first example, it's not possible to decrease the maximum used height for the problem at any intersection, hence we don't have to change any heights.

In the second example, the answers are as follows: 

  * For the intersection of the first line and the first column <image>
  * For the intersection of the first line and the second column <image>
  * For the intersection of the second line and the first column <image>
  * For the intersection of the second line and the second column <image>

Solution (in JAVA):

Solution:
import java.io.*;
import java.math.BigDecimal;
import java.util.*;

public class scratch_25 {
    static class Reader {
        static BufferedReader reader;
        static StringTokenizer tokenizer;

        /** call this method to initialize reader for InputStream */
        static void init(InputStream input) {
            reader = new BufferedReader(
                    new InputStreamReader(input) );
            tokenizer = new StringTokenizer("");
        }

        /** get next word */
        static String next() throws IOException {
            while ( ! tokenizer.hasMoreTokens() ) {
                //TODO add check for eof if necessary
                tokenizer = new StringTokenizer(
                        reader.readLine() );
            }
            return tokenizer.nextToken();
        }

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

        static double nextDouble() throws IOException {
            return Double.parseDouble( next() );
        }
        static long nextLong() throws IOException{
            return Long.parseLong(next());
        }
    }
    public static void main(String[] args) throws IOException {
        Reader.init(System.in);
        int n= Reader.nextInt();
        int m= Reader.nextInt();
        int arr[][]= new int[n][m];
        int arr1[][]= new int[n][m];
        int arr2[][]= new int[m][n];
        int max1[]= new int[n];
        int max2[]= new int[m];
        StringBuilder str= new StringBuilder();
        BufferedWriter out = new BufferedWriter(new OutputStreamWriter(System.out));
        for (int i = 0; i <n ; i++) {
            for (int j = 0; j <m ; j++) {
                arr[i][j]= Reader.nextInt();
                arr1[i][j]= arr[i][j];

            }
        }


//        System.out.println("arr=");
//       // System.out.println(Arrays.toString(arr));
//        for (int i = 0; i <n ; i++) {
//            System.out.println(Arrays.toString(arr[i]));
//        }


            for (int i = 0; i < m; i++) {
                for (int j = 0; j < n; j++) {
                    arr2[i][j] = arr[j][i];
                }
            }

            for (int i = 0; i < n; i++) {
               // sort(arr1[i], 0, m - 1);
                int end = arr.length;
                Set<Integer> set = new HashSet<Integer>();
                for (int j = 0; j < m; j++) {
                    set.add(arr1[i][j]);
                }
                TreeSet<Integer> t= new TreeSet<Integer>(set);
                int f = set.size();
                max1[i] = f;
                Arrays.fill(arr1[i], Integer.MAX_VALUE);
                Iterator it = t.iterator();
                int count = 0;
                while (it.hasNext()) {
                    arr1[i][count] = (int) it.next();
                    count++;

                }
                // System.out.println(f);


//            System.out.println(removeDuplicates(arr1[i],m));
//            System.out.println(Arrays.toString(arr1[i]));
            }
            for (int i = 0; i < m; i++) {
               // sort(arr2[i], 0, n - 1);
                Set<Integer> set = new HashSet<Integer>();
                for (int j = 0; j < n; j++) {
                    set.add(arr2[i][j]);
                }
                int f = set.size();
                TreeSet<Integer> t = new TreeSet<Integer>(set);
                max2[i] = f;
                Arrays.fill(arr2[i], Integer.MAX_VALUE);
                Iterator it = t.iterator();
                int count = 0;
                while (it.hasNext()) {
                    arr2[i][count] = (int) it.next();
                    count++;
                }
                // System.out.println(f);

                //  removeDuplicates(arr2[i],n);
            }
//        System.out.println("arr1=");
//        for (int i = 0; i <n ; i++) {
//            System.out.println(Arrays.toString(arr1[i]));
//        }
//        System.out.println("arr2=");
//        for (int i = 0; i <m ; i++) {
//            System.out.println(Arrays.toString(arr2[i]));
//        }
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < m; j++) {
                    int u = arr[i][j];
                    int res1 = Arrays.binarySearch(arr1[i], u);
                    int res2 = Arrays.binarySearch(arr2[j], u);
//                System.out.println("res1="+res1);
//                System.out.println("res2="+res2);
                    //  HashSet<Integer> hm = new HashSet<Integer>();
//                for (int k = 0; k <res1 ; k++) {
//                    hm.add(arr1[i][k]);
//                }
                    int low1 = res1;
//                HashSet<Integer> hs = new HashSet<Integer>();
//                for (int k = 0; k <res2 ; k++) {
//                    hs.add(arr2[j][k]);
//                }
                    int low2 = res2;
//                HashSet<Integer> ha = new HashSet<Integer>();
//                for (int k = res1; k <m ; k++) {
//                    ha.add(arr1[i][k]);
//                }
                    int high1 = max1[i] - res1 - 1;
                    //  HashSet<Integer> hb = new HashSet<Integer>();
//                for (int k = res2; k <n ; k++) {
//                   // System.out.println("bhosdike");
//                    hb.add(arr2[j][k]);
//                }
                    int high2 = max2[j] - res2 - 1;
                    int l = Math.max(low1, low2) + 1 + Math.max(high1, high2);
                    out.write(l + " ");


                }
                out.write("\n");
            }
            // System.out.println("ans=");
            out.close();


        }



    static void merge(int arr[], int l, int m, int r)
    {
        // Find sizes of two subarrays to be merged
        int n1 = m - l + 1;
        int n2 = r - m;

        /* Create temp arrays */
        int L[] = new int [n1];
        int R[] = new int [n2];

        /*Copy data to temp arrays*/
        for (int i=0; i<n1; ++i)
            L[i] = arr[l + i];
        for (int j=0; j<n2; ++j)
            R[j] = arr[m + 1+ j];


        /* Merge the temp arrays */

        // Initial indexes of first and second subarrays
        int i = 0, j = 0;

        // Initial index of merged subarry array
        int k = l;
        while (i < n1 && j < n2)
        {
            if (L[i] <= R[j])
            {
                arr[k] = L[i];
                i++;
            }
            else
            {
                arr[k] = R[j];
                j++;
            }
            k++;
        }

        /* Copy remaining elements of L[] if any */
        while (i < n1)
        {
            arr[k] = L[i];
            i++;
            k++;
        }

        /* Copy remaining elements of R[] if any */
        while (j < n2)
        {
            arr[k] = R[j];
            j++;
            k++;
        }
    }

    // Main function that sorts arr[l..r] using
    // merge()
    static void sort(int arr[], int l, int r)
    {
        if (l < r)
        {
            // Find the middle point
            int m = (l+r)/2;

            // Sort first and second halves
            sort(arr, l, m);
            sort(arr , m+1, r);

            // Merge the sorted halves
            merge(arr, l, m, r);
        }
    }
    static boolean ans(int check, long arr[],int n,int med,int k){
        long ans=0;
        for (int i = med; i <n ; i++) {
            if(check>=arr[i]){
                ans+=check-arr[i];
            }
        }
        return ans<=k;




    }

    static long smallestDivisor(long n)
    {
        // if divisible by 2
        if (n % 2 == 0)
            return 2;

        // iterate from 3 to sqrt(n)
        for (int i = 3; (long)i *(long) i <= n; i += 2) {
            if (n % i == 0)
                return i;
        }

        return n;
    }
    static boolean isPrime(long n)
    {
        // Corner cases
        if (n <= 1) return false;
        if (n <= 3) return true;

        // This is checked so that we can skip
        // middle five numbers in below loop
        if (n % 2 == 0 || n % 3 == 0) return false;

        for (int i = 5; i * i <= n; i = i + 6)
            if (n % i == 0 || n % (i + 2) == 0)
                return false;

        return true;
    }
static BigDecimal fd(int mid, double h, double c){
        BigDecimal a = new BigDecimal((h+c)/(2.0));
        BigDecimal b = new BigDecimal((h-c)/(2.0*mid));
        BigDecimal cd = a.add(b);
        return cd;




}
    static   int partition(double arr[],int arr1[],int arr2[], int low, int high)
    {
        double pivot = arr[high];
        int i = (low-1); // index of smaller element
        for (int j=low; j<high; j++)
        {
            // If current element is smaller than the pivot
            if (arr[j] < pivot)
            {
                i++;

                // swap arr[i] and arr[j]
                double temp = arr[i];
                arr[i] = arr[j];
                arr[j] = temp;
                int temp1=arr1[i];
                arr1[i]=arr1[j];
                arr1[j]=temp1;
                int temp2=arr2[i];
                arr2[i]=arr2[j];
                arr2[j]=temp2;

            }
        }

        // swap arr[i+1] and arr[high] (or pivot)
        double temp = arr[i+1];
        arr[i+1] = arr[high];
        arr[high] = temp;
        int temp1= arr1[i+1];
        arr1[i+1]=arr1[high];
        arr1[high]= temp1;
        int temp2= arr2[i+1];
        arr2[i+1]=arr2[high];
        arr2[high]= temp2;

        return i+1;
    }


    /* The main function that implements QuickSort()
      arr[] --> Array to be sorted,
      low  --> Starting index,
      high  --> Ending index */
    static void sort(double arr[],int arr1[],int arr2[], int low, int high)
    {
        if (low < high)
        {
            /* pi is partitioning index, arr[pi] is
              now at right place */
            int pi = partition(arr,arr1,arr2, low, high);

            // Recursively sort elements before
            // partition and after partition
            sort(arr,arr1,arr2, low, pi-1);
            sort(arr,arr1, arr2,pi+1, high);
        }
    }
    static int removeDuplicates(int arr[], int n)
    {
        // Return, if array is empty
        // or contains a single element
        if (n==0 || n==1)
            return n;

        int[] temp = new int[n];

        // Start traversing elements
        int j = 0;
        for (int i=0; i<n-1; i++)
            // If current element is not equal
            // to next element then store that
            // current element
            if (arr[i] != arr[i+1])
                temp[j++] = arr[i];

        // Store the last element as whether
        // it is unique or repeated, it hasn't
        // stored previously
        temp[j++] = arr[n-1];

        // Modify original array
        for (int i=0; i<j; i++)
            arr[i] = temp[i];

        return j;
    }




}