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.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.util.ArrayDeque;
import java.util.HashMap;
import java.util.Iterator;
import java.util.TreeSet;

public class A2 {
/*
4 5
1 1 10 1 1
1 1 20 1 1
11 13 14 15 16
1 1 10 1 1
 */
	static int R,C;
	static long b[][];
	static long ress[][];

	public static void main(String[] args) {
		JS in = new JS();
		PrintWriter out = new PrintWriter(System.out);
		R = in.nextInt();
		C = in.nextInt();
		b = new long[R][C];
		ress = new long[R][C];
		for(int i = 0; i < R; i++) {
			for(int j = 0; j < C; j++) {
				b[i][j] = in.nextLong();
			}
		}
		
		int rowId[][] = new int[R][C];
		int colId[][] = new int[R][C];
		
		int maxRId[] = new int[R];
		int maxCId[] = new int[C];
		for(int row = 0; row < R; row++) {
			TreeSet<Long> vals = new TreeSet<Long>();
			HashMap<Long, Integer> map = new HashMap<Long, Integer>();
			for(int c = 0; c < C; c++) {
				vals.add(b[row][c]);
			}
			int id = 0;
			for(long ll : vals) {
				map.put(ll, id++);
			}
			for(int c = 0; c < C; c++) rowId[row][c] = map.get(b[row][c]);
			maxRId[row] = id;
		}
		
		for(int col = 0; col < C; col++) {
			TreeSet<Long> vals = new TreeSet<Long>();
			HashMap<Long, Integer> map = new HashMap<Long, Integer>();
			for(int r = 0; r < R; r++) {
				vals.add(b[r][col]);
			}
			int id = 0;
			for(long ll : vals) {
				map.put(ll, id++);
			}
			for(int r = 0; r < R; r++) colId[r][col] = map.get(b[r][col]);
			maxCId[col] = id;
		}
		
		for(int i = 0; i < R; i++) {
			for(int j = 0; j < C; j++) {
				//get index in row
				long val = b[i][j];
				int res = maxRId[i];
				int id = rowId[i][j];
				int less = colId[i][j];
				if(less > id) res += (less-id);
							
				ress[i][j] = res;
			}
		}
		
		for(int i = 0; i < R; i++) {
			for(int j = 0; j < C; j++) {
				//get index in row
				long val = b[i][j];
				int res = maxCId[j];
				int id = colId[i][j];
				int le = rowId[i][j];
				if(le > id) res += (le-id);
								
				ress[i][j] = Math.max(ress[i][j], res);
			}
		}
		
		for(int i = 0; i < R; i++) {
			for(int j = 0; j < C; j++) {
				out.print(ress[i][j]+" ");
			}out.println();
		}
		out.close();
	}
	
	static class AVLTree<T extends Comparable<T>> implements Iterable<T>{  
		Node root;  
		boolean procEq;
		
		public void add(T val) { root = insert(root, val); }
		public void remove(T val) { root = deleteNode(root, val); }
		public boolean contains(T val) { return contains(root, val); }
		public int indexOf(T x) { return numLE(x) - 1; }
		public int numLE(T x) { return le(root, x); }
		public int numGE(T x) { return ge(root, x); }
		public int size() { return size(root); }
		public T get(int x) { return get(root, 0, x); }
		public T higher(T x) { procEq = false; return higher(root, x); }
		public T lower(T x) { procEq = false; return lower(root, x); }
		public T ceil(T x) { procEq = true; return higher(root, x); }
		public T floor(T x) { procEq = true; return lower(root, x); }
		public T last() {
			Node ptr = root;
			while(ptr.right != null) ptr = ptr.right;
			return ptr.key;
		}
		public T first() {
			Node ptr = root;
			while(ptr.left != null) ptr = ptr.left;
			return ptr.key;
		}
		public void print() {
			print(root);
		}
		public void print(Node x) {
			if(x==null) return;
			System.out.println(x.key+" "+ (x.left == null ? "null" : x.left.key)+" "+(x.right == null ? "null" : x.right.key));
			if(x.left != null) print(x.left);
			if(x.right != null) print(x.right);
		}
			
		public boolean contains(Node node, T x) {
			if(node == null) return false;
			int comp = node.key.compareTo(x);
			return comp == 0 ? true : comp < 0 ? contains(node.right, x) : contains(node.left, x);
		}
		public T higher(Node node, T x) {
			if(node == null) return null;
			if(procEq && node.key.compareTo(x) == 0) return node.key;
			if(node.key.compareTo(x) <= 0) return higher(node.right, x);
			else {
				T l = higher(node.left, x);
				if(l == null) return node.key;
				else return l;
			}
		}
		public T lower(Node node, T x) {
			if(node == null) return null;
			if(procEq && node.key.compareTo(x) == 0) return node.key;
			if(node.key.compareTo(x) >= 0) return lower(node.left, x);
			else {
				T r = lower(node.right, x);
				if(r == null) return node.key;
				else return r;
			}
		}

		public T get(Node node, int curId, int target) {
			if(node == null) return null;
			int cid = curId+size(node.left);
			if(cid == target) return node.key;
			if(cid < target) return get(node.right, 1+cid, target);	
			else return get(node.left, curId, target);
		}	
		public int le(Node node, T key) {
			if(node == null) return 0;
			if(node.key.compareTo(key) == 0) return 1 + size(node.left);
			else if(node.key.compareTo(key) < 0) {
				return 1 + size(node.left) + le(node.right, key); 
			}
			else {
				return le(node.left, key);
			}
		}
		public int ge(Node node, T key) {
			if(node == null) return 0;
			if(node.key.compareTo(key) == 0) return 1 + size(node.right);
			else if(node.key.compareTo(key) < 0) {
				return ge(node.right, key);
			}
			else {
				return 1 + size(node.right) + ge(node.left, key);
			}
		}
		

		
		int getBalance(Node N) { return N == null ? 0 : height(N.left) - height(N.right); }
		int height(Node N){ return N == null ? 0 : N.height; } 
		int size(Node N) { return N == null ? 0 : N.size; }
		
		void update(Node x) {
			x.height = 1 + Math.max(height(x.left), height(x.right));  
			x.size = 1 + size(x.left) + size(x.right);
		}
 
		Node balance(Node node, T key, boolean insert) {
			update(node);
			int balance = getBalance(node);  
			int ll = getBalance(node.left);
			int rr = getBalance(node.right);

			if (balance > 1 && (insert ? key.compareTo(node.left.key) < 0 : ll >= 0))  return rightRotate(node);  
			if (balance > 1 && (insert ? key.compareTo(node.left.key) > 0 : ll < 0))  {  
				node.left = leftRotate(node.left);  
				return rightRotate(node);  
			}  

			if (balance < -1 && (insert ? key.compareTo(node.right.key) > 0 : rr <= 0))  return leftRotate(node);  
			if (balance < -1 && (insert ? key.compareTo(node.right.key) < 0 : rr > 0))  {  
				node.right = rightRotate(node.right);  
				return leftRotate(node);  
			}  
			return node;  
		}
		Node rightRotate(Node y)  {  
			Node x = y.left;  
			Node T2 = x.right;  
			x.right = y;  
			y.left = T2;  
			update(y); 
			update(x);
			return x;  
		}  

		Node leftRotate(Node x) {  
			Node y = x.right;  
			Node T2 = y.left;  
			y.left = x;  
			x.right = T2;  
			update(x);
			update(y);
			return y;  
		}  

		Node getMin(Node node)  {  
			return node.left == null ? node : getMin(node.left);
		}  
		Node getMax(Node node) {
			return node.right == null ? node : getMax(node.right);
		}
		
		Node insert(Node node, T key)  {  
			if (node == null) return (new Node(key));  
			if (key.compareTo(node.key) < 0) node.left = insert(node.left, key);  
			else if (key.compareTo(node.key) > 0) node.right = insert(node.right, key);  
			else return node; 
			return balance(node, key, true); 
		}  
		Node deleteNode(Node root, T key)  {  
			if (root == null) return root;

			if (key.compareTo(root.key) < 0) root.left = deleteNode(root.left, key);  
			else if (key.compareTo(root.key) > 0) root.right = deleteNode(root.right, key);  
			else {  
				if ((root.left == null) || (root.right == null)) {  
					Node temp = null;  
					if (temp == root.left) temp = root.right;  
					else temp = root.left;  

					if (temp == null) {  
						temp = root;  
						root = null;  
					}  
					else root = temp;
				}  
				else {   
					Node temp = getMin(root.right);  
					root.key = temp.key;  
					root.right = deleteNode(root.right, temp.key);  
				}  
			}  
			if (root == null) return root;
			return balance(root, key, false);
		}  
		public class Node{  
			int height, size;  
			T key;
			Node left, right;  
			Node(T d)  {  
				key = d;  
				height = 1;  
				size = 1;
			}  
		}
		@Override
		public Iterator<T> iterator() {
			Iterator<T> it = new Iterator<T>() {
				private ArrayDeque<Node> pStack = new ArrayDeque<Node>();
				private ArrayDeque<Boolean> bStack = new ArrayDeque<Boolean>();
				private Node ptr = root;
				private boolean qwe = init();
				public boolean init() {
					if(ptr == null) return false;
					while(ptr.left != null) {
						pStack.addFirst(ptr);
						bStack.addFirst(false);
						ptr = ptr.left;
					}
					return true;
				}
				public Node next(Node x) {
					if(x.right != null) {
						pStack.addFirst(x);
						bStack.addFirst(true);
						x = x.right;
						while(x.left != null) {
							pStack.addFirst(x);
							bStack.addFirst(false);
							x = x.left;
						}
						return x;
					}
					else {
						while(true) {
							if(bStack.isEmpty()) return null;
							boolean b = bStack.poll();
							Node n = pStack.poll();
							if(!b) return n;
						}
					}
				}
				@Override
				public boolean hasNext() {
					return ptr != null;
				}

				@Override
				public T next() {
					T ret = ptr.key;
					ptr = next(ptr);
					return ret;
				}
			};
			return it;
		}  
	}

	
	static class JS{
		public int BS = 1<<16;
		public char NC = (char)0;
		byte[] buf = new byte[BS];
		int bId = 0, size = 0;
		char c = NC;
		double num = 1;
		BufferedInputStream in;
		
		public JS() {
			in = new BufferedInputStream(System.in, BS);
		}
		
		public JS(String s) throws FileNotFoundException {
			in = new BufferedInputStream(new FileInputStream(new File(s)), BS);
		}
		
		public char nextChar(){
			while(bId==size) {
				try {
					size = in.read(buf);
				}catch(Exception e) {
					return NC;
				}				
				if(size==-1)return NC;
				bId=0;
			}
			return (char)buf[bId++];
		}
		
		public int nextInt() {
			return (int)nextLong();
		}
		
		public long nextLong() {
			num=1;
			boolean neg = false;
			if(c==NC)c=nextChar();
			for(;(c<'0' || c>'9'); c = nextChar()) {
				if(c=='-')neg=true;
			}
			long res = 0;
			for(; c>='0' && c <='9'; c=nextChar()) {
				res = (res<<3)+(res<<1)+c-'0';
				num*=10;
			}
			return neg?-res:res;
		}
		
		public double nextDouble() {
		    while(c!='.'&&c!='-'&&(c <'0' || c>'9')) c = nextChar();
		    boolean neg = c=='-';
		    if(neg)c=nextChar();
		    boolean fl = c=='.';
		    double cur = nextLong();
		    if(fl) return neg ? -cur/num : cur/num;
		    if(c == '.') {
			double next = nextLong();
			return neg ? -cur-next/num : cur+next/num;
		    }
		    else return neg ? -cur : cur;
		}
		
		public String next() {
			StringBuilder res = new StringBuilder();
			while(c<=32)c=nextChar();
			while(c>32) {
				res.append(c);
				c=nextChar();
			}
			return res.toString();
		}
		
		public String nextLine() {
			StringBuilder res = new StringBuilder();
			while(c<=32)c=nextChar();
			while(c!='\n') {
				res.append(c);
				c=nextChar();
			}
			return res.toString();
		}

		public boolean hasNext() {
			if(c>32)return true;
			while(true) {
				c=nextChar();
				if(c==NC)return false;
				else if(c>32)return true;
			}
		}
	}
	
}