1 条题解
-
0
Order Statistics 题解
一、题目回顾(精简版)
给定数组 ,对参数 执行 次操作: 每次选出当前最大的 个元素(值相同则下标小更大),把它们各 。
定义:
- :操作后数组非降序排序的第 小值(第 阶统计量)。
- 。
要求:
- 先输出 。
- 处理 个询问:
- 单点修改 。
- 查询 。
- 查询 。
所有查询独立计算,不改变数组;修改永久生效。
二、核心观察(决定整个算法)
1. 操作等价描述
执行 轮、每轮减 个最大值,等价于:
对每个位置 ,设它被减了 次,则
且满足单调性约束: 若 或 ,则 。
2. 最终值形式
最终数组中元素 的值为:
3. 关键转化:二分阈值
存在一个阈值 ,使得:
- 满足 的元素数量 ;
- 满足 的元素数量 。
我们可以二分答案 ,判断:
最多能执行多少次“减最大 个”操作,使得所有 。
这就是标程中
chk(t,m)函数的本质。
三、核心函数:chk(t, m) 含义
定义:
$$\mathrm{chk}(V, m) = \sum_{a_i \ge V} \min(m,\ a_i - V) + \sum_{V-1 < a_i < V} (a_i - (V-1)) $$直观意义:
把所有数“压到不低于 ”,至少需要减掉多少总量。
我们要二分最小的 ,满足
这个 就是最终数组的分界值,大部分数会落在 或 。
四、最终数组结构
二分得到分界值 后,最终数组 只有三类:
- :极大值,被减满 次。
- :中间层,恰好减到阈值。
- :底层,减到阈值下一层。
- 更小的数:原本就远小于阈值,不受影响。
标程中
mlen就是恰好等于 的元素个数。
五、求阶统计量与区间和
我们需要:
- 对最终 数组排序;
- 求第 小;
- 求区间 的和。
1. 排序后取值分布
排序后数组从低到高:
- 一堆 的数;
- 一堆 ;
- 一堆 ;
- 一堆 的数。
2. 快速统计:树状数组 BIT
离散化所有 与修改值,维护两颗 BIT:
- :统计值域上的元素个数;
- :统计值域上的元素和。
这样可以 完成:
- 个数前缀和 二分找第 小;
- 和前缀和 区间和。
这就是标程
query_k与solve的作用。
六、整体流程
步骤 1:离线离散化
把所有初始 和所有修改操作的新值收集起来,离散化,压缩值域。
步骤 2:初始化 BIT
步骤 3:处理初始输出
对每个 :
- 二分阈值 ;
- 用 计算排序后第 小值;
- 输出。
步骤 4:处理询问
- 修改操作:在 BIT 中删去旧值,加入新值。
- 查询 1/3:调用 ,返回排序后 的和。
七、关键函数公式化
1. 二分阈值
ll L = -INF, R = max_a; while (L < R) { ll mid = (L + R) / 2; if (chk(mid, m) > m * k) L = mid + 1; else R = mid; }对应数学条件:
$$\mathrm{chk}(V, m) \le mk \quad\Rightarrow\quad \text{合法} $$2. 统计第 k 小
ll qry(int l, int r, ll d)表示:
值域 中,取最大的 个数的和。
利用 BIT 二分实现。
3. 总答案
$$S(l,r) = \mathrm{solve}(t,m,mlen, n-l+1) - \mathrm{solve}(t,m,mlen, n-r) $$即排序后后缀和相减得到 的和。
八、复杂度分析
- 离散化:
- 单次询问 :
- 二分 :
- 每次 :
- 统计 :
- 总体: 可轻松通过 ,时限 。
- 1
信息
- ID
- 6388
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 2
- 已通过
- 1
- 上传者