2021 插入排序 · 方案二 增量维护有序表
改一个元素只挪它自己,询问 O(1)
正文
// CSP-J 2021 复赛 T2 · 插入排序(方案二 · 满分)
// 原题:https://oj.yecheng.tv/p/CSPJ2021B
//
// 方案二 · 维护一张有序表,改一个元素只动 O(n)
// 排序结果只取决于 (值, 原下标) 的相对顺序。改一个元素时,
// 整张表的其它部分一点没变,只有被改的那个元素需要挪位置。
// 于是维护数组 ord(按 (值, 原下标) 排好的编号)和 pos[id](id 在 ord 里的下标):
// 修改 x:先在 ord 里把 x 摘掉(后面的往前挪一格),改值,
// 再从后往前找到它该待的位置,整体往后挪一格塞进去;
// 询问 x:直接输出 pos[x] + 1,O(1)。
// 一次修改 O(n),题目保证修改最多 5000 次,5000 * 8000 = 4e7,稳过。
//
// 小提醒:stable_sort 也能得到同样的结果,但每次修改都重排是 O(n log n),
// 5000 次下来大约是 5e8 次比较,容易被卡常 —— 增量维护更稳。
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 8005;
int a[MAXN];
int ord[MAXN]; // 有序表:按 (值, 原下标) 排好的元素编号
int pos[MAXN]; // pos[id] = id 在 ord 中的下标
int len;
// u 是否应该排在 v 前面:先比值,值一样就比原下标(保证稳定)
bool before(int u, int v) {
if (a[u] != a[v]) return a[u] < a[v];
return u < v;
}
int main() {
freopen("sort.in", "r", stdin);
freopen("sort.out", "w", stdout);
int n, Q;
cin >> n >> Q;
vector<int> ids(n);
for (int i = 1; i <= n; i++) {
cin >> a[i];
ids[i - 1] = i;
}
sort(ids.begin(), ids.end(), before);
len = n;
for (int i = 0; i < n; i++) {
ord[i] = ids[i];
pos[ids[i]] = i;
}
while (Q--) {
int op;
cin >> op;
if (op == 1) {
int x, v;
cin >> x >> v;
int p = pos[x];
for (int i = p; i + 1 < len; i++) { // 摘掉 x,后面的往前挪
ord[i] = ord[i + 1];
pos[ord[i]] = i;
}
len--;
a[x] = v;
int q = len;
while (q > 0 && before(x, ord[q - 1])) q--; // 找新位置
for (int i = len; i > q; i--) { // 整体后挪一格
ord[i] = ord[i - 1];
pos[ord[i]] = i;
}
ord[q] = x;
pos[x] = q;
len++;
} else {
int x;
cin >> x;
cout << pos[x] + 1 << "\n";
}
}
return 0;
}
CSP-J 标程 · 复赛真题的其它内容
- 2019 数字游戏 · 方案一 逐字符统计
- 2019 数字游戏 · 方案二 二进制位运算
- 2020 优秀的拆分 · 方案一 贪心从大到小减
- 2020 优秀的拆分 · 方案二 直接看二进制位
- 2021 分糖果 · 方案一 枚举每个 k
- 2021 分糖果 · 方案二 看余数在哪一段
- 2022 乘方 · 方案一 边乘边判断
- 2022 乘方 · 方案二 快速幂加封顶
- 2023 小苹果 · 方案一 照规则真模拟
- 2023 小苹果 · 方案二 只盯住两个数字
- 2024 扑克牌 · 方案一 用集合去重
- 2024 扑克牌 · 方案二 二维布尔表
- 2025 拼数 · 方案一 收集后降序排序
- 2025 拼数 · 方案二 桶计数
- 2019 公交换乘 · 方案一 暴力匹配
- 2019 公交换乘 · 方案二 时间窗口优化
- 2020 直播获奖 · 方案一 每轮排序
- 2020 直播获奖 · 方案二 桶计数
- 2021 插入排序 · 方案一 每次真排一遍
- 2022 解密 · 方案一 二分求整数平方根
- 2022 解密 · 方案二 先估后校开方
- 2023 公路 · 方案一 朴素贪心
- 2023 公路 · 方案二 单调栈预处理
- 2024 地图探险 · 方案一 四方向分支写
- 2024 地图探险 · 方案二 方向数组
- 2025 座位 · 方案一 把座位表填出来
- 2025 座位 · 方案二 直接算排名
- 2019 纪念品 · 方案一 逐天完全背包
- 2019 纪念品 · 方案二 砍掉不赚钱物品
- 2020 表达式 · 方案一 每次重算后缀式
- 2020 表达式 · 方案二 建树加关键性传播
- 2021 网络连接 · 方案一 手写解析
- 2021 网络连接 · 方案二 读入后回拼校验
- 2022 逻辑表达式 · 方案一 递归分治
- 2022 逻辑表达式 · 方案二 递归下降
- 2023 一元二次方程 · 方案一 照公式逐步写
- 2023 一元二次方程 · 方案二 拆成小函数
- 2024 小木棍 · 方案一 先定位数再贪心
- 2024 小木棍 · 方案二 预处理最小数字表
- 2025 异或和 · 方案一 贪心能接就接
- 2025 异或和 · 方案二 动态规划加值域数组
- 2019 加工零件 · 方案一 递归加记忆化
- 2019 加工零件 · 方案二 奇偶最短路
- 2020 方格取数 · 方案一 深搜回溯
- 2020 方格取数 · 方案二 按列动态规划
- 2021 小熊的果篮 · 方案一 每轮扫一遍
- 2021 小熊的果篮 · 方案二 链表加有序集合
- 2022 上升点列 · 方案一 先只考虑不加点
- 2022 上升点列 · 方案二 二维动态规划
- 2023 旅游巴士 · 方案一 分层图加优先队列
- 2023 旅游巴士 · 方案二 状态压成一维
- 2024 接龙 · 方案一 按定义广搜
- 2024 接龙 · 方案二 滑动窗口逐轮推进
- 2025 多边形 · 方案一 枚举所有子集
- 2025 多边形 · 方案二 排序加计数 DP