codeforces Codeforces Round #345 (Div. 1) C. Table Compression 排序+并查集

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 iof the initial table ai, j < ai, k, then in the resulting table a'i, j < a'i, k, and if ai, j = ai, k then a'i, j = a'i, k. Similarly, if in some column j of the initial table ai, j < ap, j then in compressed table a'i, j < a'p, j and if ai, j = ap, j then a'i, j = a'p, j.

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.

Input

The first line of the input contains two integers n and m (, the number of rows and the number of columns of the table respectively.

Each of the following n rows contain m integers ai, j (1 ≤ ai, j ≤ 109) that are the values in the table.

Output

Output the compressed table in form of n lines each containing m integers.

If there exist several answers such that the maximum number in the compressed table is minimum possible, you are allowed to output any of them.

Examples
Input
2 2
1 2
3 4
Output
1 2
2 3
Input
4 3
20 10 30
50 40 30
50 60 70
90 80 70
Output
2 1 3
5 4 3
5 6 7
9 8 7
Note

In the first sample test, despite the fact a1, 2 ≠ a21, they are not located in the same row or column so they may become equal after the compression.

题意:个数不超过1e6个数的二维数列;按照行与列数的相对大小尽可能的缩小为正整数,但不在同一行或同一列的数的缩放前后的大小没有关系;

输出缩放后的数列;

思路:排序后每次处理都是处理值相等的一串数据,并且是看成没没有填入到新数组中,这样使用并查集就可以得到“十”字形相等的根节点的最大值,即所有这棵并查集下的节点的值;x[i],y[i]来模拟并查集,X[],Y[]表示行列上一个值填到的数值,所以之后直接得到根节点所要填入的值;

复制代码
#include<bits/stdc++.h>
using namespace std;
int i,j,k,n,m,T,tot;
const int N = 1000100;
struct data{
    int r,c,v,id;
}p[N];
bool cmp(const data &a,const data &b){return a.v < b.v;}
int f[N],X[N],Y[N],ans[N],x[N],y[N],tmp[N];
int Find(int a){return a==f[a]?f[a]:f[a]=Find(f[a]);}
int main()
{
    scanf("%d%d",&n,&m);
    for(i = 1;i <= n;i++)
    for(j = 1;j <= m;j++){
        scanf("%d",&p[++tot].v);
        p[tot].r = i,p[tot].c = j;
        p[tot].id = tot;
        f[tot] = tot;
    }
    sort(p+1,p+1+tot,cmp);
    for(i = 1;i <= tot;i = j){
        for(j = i;p[i].v == p[j].v;++j);
        for(k = i;k < j;k++){
            int r = p[k].r, c = p[k].c;
            if(!x[r]) x[r] = k;// 行并查
            else f[Find(k)] = Find(x[r]);
            if(!y[c]) y[c] = k;
            else f[Find(k)] = Find(y[c]);//f[k]会因为十字型交叉而出错;
        }
        for(k = i;k < j;k++){//只是在之前的值的基础上得到,不是模拟填入值
            int q = Find(k);
            tmp[q] = max(tmp[q],max(X[p[k].r],Y[p[k].c])+1);
        }
        for(k = i;k < j;k++){//根节点得到的是全体的值
            x[p[k].r] = y[p[k].c] = 0;
            X[p[k].r] = Y[p[k].c] = ans[p[k].id] = tmp[Find(k)];
        }
    }
    for(i = 1;i <= tot;i++){
        printf("%d ",ans[i]);
        if(i%m == 0) puts("");
    }
}
复制代码
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值