Little Petya is now fond of data compression algorithms. He has already studied gz, bz, zip algorithms and many others. Inspired by the new knowledge, Petya is now developing the new compression algorithm which he wants to name dis.

Petya decided to compress tables. He is given a table *a* consisting of *n* rows and *m* columns that is filled with positive integers. He wants to build the table *a*' consisting of positive integers such that the relative order of the elements in each row and each column remains the same. That is, if in some row *i* of the initial table *a*<sub class="lower-index">*i*, *j*</sub> &lt; *a*<sub class="lower-index">*i*, *k*</sub>, then in the resulting table *a*'<sub class="lower-index">*i*, *j*</sub> &lt; *a*'<sub class="lower-index">*i*, *k*</sub>, and if *a*<sub class="lower-index">*i*, *j*</sub> = *a*<sub class="lower-index">*i*, *k*</sub> then *a*'<sub class="lower-index">*i*, *j*</sub> = *a*'<sub class="lower-index">*i*, *k*</sub>. Similarly, if in some column *j* of the initial table *a*<sub class="lower-index">*i*, *j*</sub> &lt; *a*<sub class="lower-index">*p*, *j*</sub> then in compressed table *a*'<sub class="lower-index">*i*, *j*</sub> &lt; *a*'<sub class="lower-index">*p*, *j*</sub> and if *a*<sub class="lower-index">*i*, *j*</sub> = *a*<sub class="lower-index">*p*, *j*</sub> then *a*'<sub class="lower-index">*i*, *j*</sub> = *a*'<sub class="lower-index">*p*, *j*</sub>. 

Because large values require more space to store them, the maximum value in *a*' should be as small as possible.

Petya is good in theory, however, he needs your help to implement the algorithm.
The first line of the input contains two integers *n* and *m* (<img align="middle" class="tex-formula" src="https://espresso.codeforces.com/8ce9eb3b66e2ccbb79eae736994b3703b3b8e7d2.png" style="max-width: 100.0%;max-height: 100.0%;"/>, the number of rows and the number of columns of the table respectively.

Each of the following *n* rows contain *m* integers *a*<sub class="lower-index">*i*, *j*</sub> (1 ≤ *a*<sub class="lower-index">*i*, *j*</sub> ≤ 10<sup class="upper-index">9</sup>) that are the values in the table.
In the first sample test, despite the fact *a*<sub class="lower-index">1, 2</sub> ≠ *a*<sub class="lower-index">21</sub>, they are not located in the same row or column so they may become equal after the compression.
#                    _ooOoo_
#                   o8888888o
#                   88" . "88
#                   (| -_- |)
#                   O\  =  /O
#                ____/`---'\____
#              .'  \\|     |//  `.
#             /  \\|||  :  |||//  \
#            /  _||||| -:- |||||-  \
#            |   | \\\  -  /// |   |
#            | \_|  ''\---/''  |   |
#            \  .-\__  `-`  ___/-. /
#          ___`. .'  /--.--\  `. . __
#       ."" '<  `.___\_<|>_/___.'  >'"".
#      | | :  `- \`.;`\ _ /`;.`/ - ` : | |
#      \  \ `-.   \_ __\ /__ _/   .-` /  /
# ======`-.____`-.___\_____/___.-`____.-'======
#                    `=---='
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#             佛祖保佑       永无BUG

import sys
# sys.setrecursionlimit(int(1e9))
# import random
from copy import deepcopy
from collections import Counter, defaultdict, deque
from functools import lru_cache, reduce
# from itertools import accumulate,product
from heapq import nsmallest, nlargest, heapify, heappop, heappush
# from bisect import bisect_left,bisect_right
from sortedcontainers import *
# input = sys.stdin.buffer.readline
# import re
input = lambda:sys.stdin.readline().rstrip("\r\n")
def mp():return list(map(int,input().split()))
def it():return int(input())
from math import *

MOD = int(1e9 + 7)
INF = int(1e18)

class LazySegmentTree:
    __slots__ = ["op_X", "e_X", "mapping", "compose", "id_M", "N", "log", "N0", "data", "lazy"]

    def __init__(self, op_X, e_X, mapping, compose, id_M, N, array=None):
        self.e_X = e_X
        self.op_X = op_X
        self.mapping = mapping
        self.compose = compose
        self.id_M = id_M
        self.N = N
        self.log = (N - 1).bit_length()
        self.N0 = 1 << self.log
        self.data = [e_X] * (2 * self.N0)
        self.lazy = [id_M] * self.N0
        if array is not None:
            assert N == len(array)
            self.data[self.N0:self.N0 + self.N] = array
            for i in range(self.N0 - 1, 0, -1):
                self.update(i)

    def prod(self, l, r):
        if l == r: return self.e_X
        l += self.N0
        r += self.N0
        for i in range(self.log, 0, -1):
            if (l >> i) << i != l:
                self.push(l >> i)
            if (r >> i) << i != r:
                self.push(r >> i)

        sml = smr = self.e_X
        while l < r:
            if l & 1:
                sml = self.op_X(sml, self.data[l])
                l += 1
            if r & 1:
                r -= 1
                smr = self.op_X(self.data[r], smr)
            l >>= 1
            r >>= 1
        return self.op_X(sml, smr)

    def all_prod(self):
        return self.data[1]

    def apply(self, p, f):
        p += self.N0
        for i in range(self.log, 0, -1):
            self.push(p >> i)
        self.data[p] = self.mapping(f, self.data[p])
        for i in range(1, self.log + 1):
            self.update(p >> i)

    def apply(self, l, r, f):
        if l == r: return
        l += self.N0
        r += self.N0
        for i in range(self.log, 0, -1):
            if (l >> i) << i != l:
                self.push(l >> i)
            if (r >> i) << i != r:
                self.push((r - 1) >> i)

        l2, r2 = l, r
        while l < r:
            if l & 1:
                self.all_apply(l, f)
                l += 1
            if r & 1:
                r -= 1
                self.all_apply(r, f)
            l >>= 1
            r >>= 1

        l, r = l2, r2
        for i in range(1, self.log + 1):
            if (l >> i) << i != l:
                self.update(l >> i)
            if (r >> i) << i != r:
                self.update((r - 1) >> i)


    def update(self, k):
        self.data[k] = self.op_X(self.data[2 * k], self.data[2 * k + 1])

    def all_apply(self, k, f):
        self.data[k] = self.mapping(f, self.data[k])
        if k < self.N0:
            self.lazy[k] = self.compose(f, self.lazy[k])

    def push(self, k): 
        if self.lazy[k] is self.id_M: return
        self.data[2 * k] = self.mapping(self.lazy[k], self.data[2 * k])
        self.data[2 * k + 1] = self.mapping(self.lazy[k], self.data[2 * k + 1])
        if 2 * k < self.N0:
            self.lazy[2 * k] = self.compose(self.lazy[k], self.lazy[2 * k])
            self.lazy[2 * k + 1] = self.compose(self.lazy[k], self.lazy[2 * k + 1])
        self.lazy[k] = self.id_M

e_X = INF
id_M = 0


def op_X(X, Y):
    return min(X,Y)

def compose(f, g):
    return f+g


def mapping(f, X):
    return f+X


class UnionFind:
    def __init__(self, n: int):
        self.root = [-1] * n
 
    def find(self, x: int) -> int:
        if self.root[x] < 0:
            return x
        self.root[x] = self.find(self.root[x])
        return self.root[x]
 
    def unite(self, x: int, y: int) -> bool:
        x = self.find(x)
        y = self.find(y)
        if x == y:
            return False
        if self.root[x] > self.root[y]:
            x, y = y, x
        self.root[x] += self.root[y]
        self.root[y] = x
        return True
 
    def is_same(self, x: int, y: int) -> bool:
        return self.find(x) == self.find(y)
 
    def size(self, x: int) -> int:
        return self.root[self.find(x)] * -1
 
    def members(self, x):
        par = self.find(x)
        return [i for i in range(n) if self.find(i) == par]
 
    def roots(self):
        return [i for i, x in enumerate(self.root) if x < 0]
 
    def group_count(self):
        return len(self.roots())
 
    def all_group_members(self):
        return {r: self.members(r) for r in self.roots()}
 
    def __str__(self):
        return '\n'.join('{}: {}'.format(r, self.members(r)) for r in self.roots())

def solve():
    n,m=mp()
    # nums=mp()
    # seg=LazySegmentTree(op_X,INF,mapping,compose,id_M,n,nums)
    matrix=[]
    for i in range(n):
        matrix.append(mp())
    ans=[[0]*m for _ in range(n)]
    record=defaultdict(list)
    for i in range(n):
        for j in range(m):
            record[matrix[i][j]].append((i,j))
    col,row=[0]*m,[0]*n
    for x in sorted(record):
        uf,rank=UnionFind(n+m),defaultdict(int)
        for i,j in record[x]:
            uf.unite(i,j+n)
        for i,j in record[x]:
            rank[uf.find(i)]=max(rank[uf.find(i)],col[j],row[i])
        for i,j in record[x]:
            ans[i][j]=row[i]=col[j]=1+rank[uf.find(i)]
    for a in ans:
        print(*a)

    return

if __name__ == '__main__':

    # t=it()
    # for _ in range(t):
    #     solve()

    # n=it()
    # n,m,i=mp()
    # n,m=mp()
    solve()