[模板]离散化

离散化基于这样一种思想:当想要存储的数据的量较小,而数值较大,并且操作对象是数值时,使用数值的排名来代表数值进行操作.

与哈希算法很相似,不过这种算法一定不会发生冲突,但是预处理复杂度为O(NlogN),单次查询的复杂度是O(logN).

 给出的数在32位有符号整数范围内.

如果每当一个数字第一次出现时,将其记录为已出现,当下一次出现时就可以忽略它了.

为了进行这样的记录,使用排名代表数字,使得每个数字(重复视为同一个数字)与其排名形成一一对应关系.使用discrete函数构建这种关系:

// 假设给定的ind个数据已经复制到了dis数组中
void discrete() {    // O(NlogN)
    sort(dis + 1, dis + 1 + ind);
    ind = unique(dis + 1, dis + 1 + ind) - dis - 1;    // unique的复杂度是O(N)
}

现在dis数组中就有了排序并去重后的数字,排名为i的数字为dis[i]的值.之后处理dis[i]时用i代替之.

例如,读取到一个数字123456789,使用query函数获取其排名:

// O(logN)
int query(int x) { return lower_bound(dis + 1, dis + 1 + ind, x) - dis; }

假设query(123456789)返回了5,那么检查排名为5的数字是否已经出现过了(used[5] == true),如果没有出现过就输出dis[5]并标记为已出现,否则直接读取下一个数字.

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
#define SIZE 50000

int s[SIZE + 10], dis[SIZE + 10], idx;
bool used[SIZE + 10];

inline int read() {
    char ch = getchar();
    int x = 0, f = 1;
    while (ch > '9' || ch < '0') {
        if (ch == '-') f = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9') {
        x = x * 10 + ch - '0';
        ch = getchar();
    }
    return x * f;
}
void discrete() {
    sort(dis + 1, dis + 1 + idx);
    idx = unique(dis + 1, dis + 1 + idx) - dis - 1;
}
int query(int x) { return lower_bound(dis + 1, dis + 1 + idx, x) - dis; }

void solve() {
    int n = read();
    idx = 0;
    memset(used, 0, sizeof(bool) * (n + 1));
    for (int i = 1; i <= n; i++) {
        s[i] = read();
        dis[++idx] = s[i];
    }
    discrete();

    for (int i = 1; i <= n; i++) {
        int ns = query(s[i]);
        if (!used[ns]) {
            printf("%d ", s[i]);
            used[ns] = true;
        }
    }
    puts("");
}

int main() {
    int t;
    t = read();
    while (t--) solve();

    return 0;
}
P4305
原文地址:https://www.cnblogs.com/Gaomez/p/14255620.html