CF 651 E 并查集(矩阵关系不变) 挺好的

23 篇文章 0 订阅

E. Table Compression
time limit per test
4 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Little Petya is now fond of data compression algorithms. He has already studied gzbzzip 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 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.



题目大意:

给你一个矩阵,然后修改矩阵,让所有的列和行的大小关系保持不变


思路:

感觉这道题犯2了好久,看别人的思路半天都不知道该怎么做,然后试着敲了一下,结果原因是因为operate这里错了,然后果断直接改成了cmp,还是简单粗暴一点的比较好。

首先因为范围很大,刚开始我想的是排序以后离散化,但是离散化以后就不会做了。。。

然后看了一下题解以后发现,通过并查集来维护关系。

首先我们从大到小排序以后,然后从第一个开始枚举所有的数字,然后遇到相同的数字就continue,并用lb来维护左端的值。接着,我们将所有值相同的,同一行同一列的都保存为一个点(利用并查集的路径压缩),并且在这个时候要记得将cnt的值不断更新。

然后跳出当前循环以后,我们要重新枚举当前的ans值,然后再这个之中我们也要记得维护maxx和maxy(当前行列的最大值)的值,就可以了。



#include
   
   
    
    

using namespace std;

const int maxn = 1000000 + 5;
int n, m;
struct point{
    int x, y;
    int val;
};
point my[maxn], mx[maxn];
point now[maxn];
int ans[maxn], cnt[maxn], par[maxn];
int maxx[maxn], maxy[maxn];

int cal(int x, int y){
    return x * m + y;
}

void init(){
    scanf("%d%d", &n, &m);
    for (int i = 0; i < n; i++){
        for (int j = 0; j < m; j++){
            int tmp;
            scanf("%d", &tmp);
            int p = cal(i, j);
            now[p].x = i;
            now[p].y = j;
            now[p].val = tmp;
            par[p] = p;
        }
    }
}

int pfind(int x){
    if (par[x] == x) return x;
    return par[x] = pfind(par[x]);
}

xcheck(int x, int y, int val, int r){
    if (mx[x].val < val){
        mx[x].val = val;
        mx[x].x = x;
        mx[x].y = y;
    }
    else {
        int px = cal(mx[x].x, mx[x].y);
        px = pfind(px);
        if (r != px){
            cnt[r] = max(cnt[r], cnt[px]);
            par[px] = r;
        }
    }
}

void ycheck(int x, int y, int val, int r){
    if (my[y].val < val){
        my[y].val = val;
        my[y].x = x;
        my[y].y = y;
    }
    else {
        int py = cal(my[y].x, my[y].y);
        py = pfind(py);
        if (py != r){
            cnt[r] = max(cnt[r], cnt[py]);
            par[py] = r;
        }
    }
}

bool cmp (const point &a, const point &b){
    return a.val < b.val;
}

void solve(){
    sort(now, now + n * m, cmp);
    //printf("%d %d %d\n", now[1].x, now[1].y, now[1].val);
    int lb = 0;
    for (int i = 1; i <= n*m; i++){
        if (now[i].val == now[i - 1].val) continue;
        int g = i - 1;
        for (int j = lb; j <= g; j++){
            int x = now[j].x;
            int y = now[j].y;
            int val = now[j].val;
            int r = cal(x, y);
            r = pfind(r);
            xcheck(x, y, val, r);
            ycheck(x, y, val, r);
            cnt[r] = max(cnt[r], max(maxx[x], maxy[y]));
        }
        for (int j = lb; j <= g; j++){
            int pla = cal(now[j].x, now[j].y);
            //printf("pla = %d\n", pla);
            int ro = pfind(pla);
            //if (j == 3) printf("cnt[3] = %d r = %d pla = %d\n", cnt[pfind(j)], pfind(j), pla);
            ans[pla] = cnt[ro] + 1;

            maxx[now[j].x] = max(maxx[now[j].x], ans[pla]);
            maxy[now[j].y] = max(maxy[now[j].y], ans[pla]);
        }
        //printf("%d\n", lb);


        lb = i;

    }
    for (int i = 0; i < n; i++){
        for (int j = 0; j < m; j++){
            printf("%d%c", ans[cal(i, j)], j == m-1 ? '\n' : ' ');
        }
    }
}

int main(){
    init();
    solve();
    return 0;
}

   
   





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值