zoukankan      html  css  js  c++  java
  • CF650C Table Compression

    CF650C Table Compression

    给一个 (n imes m) 的非负整数矩阵 (a),让你求一个 (n imes m) 的非负整数矩阵 (b),满足以下条件

    1. (a_{i,j}<a_{i,k}),则 (b_{i,j}<b_{i,k})
    2. (a_{i,j}=a_{i,k}),则 (b_{i,j}=b_{i,k})
    3. (a_{i,j}<a_{k,j}),则 (b_{i,j}<b_{k,j})
    4. (a_{i,j}=a_{k,j}),则 (b_{i,j}=b_{k,j})
    5. (b) 中的最大值最小

    (n imes mleq 10^6)

    建图+并查集


    先考虑 (a) 中没有重复元素的情况

    发现,我们只需要对于每行每列,按值域从小到大,相邻两位置连边,然后 (b) 每个位置的权值即为到最小数的距离,在 DAG 上遍历一遍即可

    但是若 (a) 中有重复元素,直接建图就没有正确性了

    (trick) :对于同一行同一列的重复元素,建立并查集,进行操作时只用对根节点进行操作

    时间复杂度 (O(nmlog nm))

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    #define get(x, y) ((x - 1) * m + y)
    typedef pair <int, int> pii;
    const int maxn = 1e6 + 10;
    int n, m, tot, a[maxn], f[maxn], par[maxn];
    struct node {
      int x, y;
      bool operator < (const node& o) const {
        return a[get(x, y)] < a[get(o.x, o.y)];
      }
    } dat[maxn];
    vector <int> g[maxn];
    
    int find(int x) {
      return par[x] == x ? x : par[x] = find(par[x]);
    }
    
    void unite(int x, int y) {
      par[find(x)] = find(y);
    }
    
    int dfs(int u) {
      if (~f[u]) return f[u]; f[u] = 0;
      for (int v : g[u]) f[u] = max(f[u], dfs(v));
      return ++f[u];
    }
    
    int main() {
      scanf("%d %d", &n, &m), tot = n * m;
      for (int i = 1; i <= tot; i++) {
        scanf("%d", a + i), par[i] = i;
      }
      for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
          dat[j] = node{i, j};
        }
        sort(dat + 1, dat + m + 1);
        for (int j = 1; j < m; j++) {
          int u = get(dat[j].x, dat[j].y);
          int v = get(dat[j + 1].x, dat[j + 1].y);
          if (a[u] == a[v]) unite(u, v);
        }
      }
      for (int j = 1; j <= m; j++) {
        for (int i = 1; i <= n; i++) {
          dat[i] = node{i, j};
        }
        sort(dat + 1, dat + n + 1);
        for (int i = 1; i < n; i++) {
          int u = get(dat[i].x, dat[i].y);
          int v = get(dat[i + 1].x, dat[i + 1].y);
          if (a[u] == a[v]) unite(u, v);
        }
      }
      for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
          dat[j] = node{i, j};
        }
        sort(dat + 1, dat + m + 1);
        for (int j = 1; j < m; j++) {
          int u = get(dat[j].x, dat[j].y);
          int v = get(dat[j + 1].x, dat[j + 1].y);
          if ((u = find(u)) != (v = find(v))) g[v].push_back(u);
        }
      }
      for (int j = 1; j <= m; j++) {
        for (int i = 1; i <= n; i++) {
          dat[i] = node{i, j};
        }
        sort(dat + 1, dat + n + 1);
        for (int i = 1; i < n; i++) {
          int u = get(dat[i].x, dat[i].y);
          int v = get(dat[i + 1].x, dat[i + 1].y);
          if ((u = find(u)) != (v = find(v))) g[v].push_back(u);
        }
      }
      memset(f, -1, sizeof f);
      for (int i = 1; i <= tot; i++) {
        if (find(i) == i) dfs(i);
      }
      for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
          printf("%d ", f[find(get(i, j))]);
        }
        putchar(10);
      }
      return 0;
    }
    

    一种 (shortest) 的做法

    对于每个元素,按值域从小到大考虑,通过已访问到的行列最大值更新答案

    时间复杂度 (O(nmlog nm))

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    #define get(x, y) ((x - 1) * m + y)
    const int maxn = 1e6 + 10;
    int n, m, tot, a[maxn], ans[maxn], par[maxn], val[2][maxn];
    struct node {
      int x, y;
      bool operator < (const node& o) const {
        return a[get(x, y)] < a[get(o.x, o.y)];
      }
    } dat[maxn];
    
    int find(int x) {
      return par[x] == x ? x : par[x] = find(par[x]);
    }
    
    int main() {
      scanf("%d %d", &n, &m), tot = n * m;
      for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
          int pos = get(i, j);
          scanf("%d", a + pos), dat[pos] = node{i, j}, par[pos] = pos;
        }
      }
      sort(dat + 1, dat + tot + 1);
      for (int i = 1; i <= tot; i++) {
        int tx = dat[i].x, ty = dat[i].y, pos = get(tx, ty);
        int px = find(val[0][tx]), py = find(val[1][ty]), p = find(pos);
        ans[p] = max(ans[px] + (a[p] > a[px]), ans[py] + (a[p] > a[py]));
        if (a[p] == a[px]) par[px] = p;
        if (a[p] == a[py]) par[py] = p;
        val[0][tx] = val[1][ty] = p;
      }
      for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
          printf("%d ", ans[find(get(i, j))]);
        }
        putchar(10);
      }
      return 0;
    }
    
  • 相关阅读:
    Docker系列
    Eclipse 安装TestNG插件,结合Maven使用
    HttpClient设置忽略SSL,实现HTTPS访问, 解决Certificates does not conform to algorithm constraints
    Jenkins Html Rport 使用frame报错解决办法
    Zend Framework1 框架入门(针对Windows,包含安装配置与数据库增删改查)
    Windows下Nginx配置SSL实现Https访问(包含证书生成)
    Windows下Nginx Virtual Host多站点配置详解
    幽灵般的存在:零宽空白
    我的公司培训讲义(2):设计模式思想精要教程
    突如其来而又必然的离职
  • 原文地址:https://www.cnblogs.com/Juanzhang/p/10424880.html
Copyright © 2011-2022 走看看