排序与离散化CSP-J

目录

💡 核心思想

排序是将数据按特定顺序排列的操作,是算法竞赛的基础工具。离散化是将大范围的数值映射到紧凑的小范围,常用于坐标压缩,是处理大数据范围的重要技巧。

竞赛中几乎不会让你手写排序算法——直接用 sort()。但你必须理解各种排序的特点:稳定排序 vs 不稳定排序、$O(n \log n)$ 的下界。离散化是个非常实用的技巧:当值域很大但实际值很少时(比如坐标是 $10^9$ 级别但只有 $10^5$ 个),离散化后用下标操作就方便多了。

🎯 直觉理解

排序就像整理书架上的书——按作者名排序。离散化就像把"第1排第1000000000列"简化为"第3个位置"——重要的不是绝对位置,而是相对顺序。

📝 算法流程

  1. 排序:使用 STL sort(),自定义比较函数
  2. 离散化:排序 → 去重 → 二分查找映射
  3. 注意 stable_sort() 保证相等元素原有顺序

$$\text{离散化:} a_i \mapsto \text{rank}(a_i) = \text{lower_bound(sorted, } a_i) - sorted.begin() + 1$$

📊 复杂度分析

指标复杂度
时间排序 $O(n \log n)$,离散化 $O(n \log n)$
空间$O(n)$

💻 参考实现(C++)

C++ (C++17)
#include <bits/stdc++.h>
using namespace std;
// 排序 + 离散化模板
int main() {
    int n; cin >> n;
    vector<int> a(n), b;
    for (auto& x : a) cin >> x;
    b = a;
    sort(b.begin(), b.end());
    b.erase(unique(b.begin(), b.end()), b.end()); // 去重
    // 离散化:a[i] 映射为 1-based rank
    for (auto& x : a) {
        x = lower_bound(b.begin(), b.end(), x) - b.begin() + 1;
    }
    for (auto x : a) cout << x << ' ';
    return 0;
}

⚠️ 常见坑点

离散化忘记去重导致映射错误

自定义比较函数不满足严格弱序(< 中的等号问题)

sort() 的比较函数里用 <= 导致运行时错误

结构体排序忘记重载 < 或传比较函数

📚 相关题目

题目来源难度备注
P1059 明明的随机数洛谷CSP-J排序去重
P1966 火柴排队洛谷CSP-S离散化+逆序对