Loading

研究对象的启示——排序问题 题解

排序问题 题解

题目描述

你有 \(n\) 个数,你想把它们从小到大排序。你使用了冒泡排序。对于每一轮,你都会依次执行:

  • 比较第一个数和第二个数。如果第二个数更小,交换它们的位置。

  • 比较第二个数和第三个数。如果第三个数更小,交换它们的位置。

  • ...

  • 比较第 \(n-1\) 个数和第 \(n\) 个数。如果第 \(n\) 个数更小,交换它们的位置。

\(q\) 个询问,每次问 \(l,r,x,y,z\) 表示对初始序列中位置 \(l\)\(r\) 的子序列应用冒泡排序的进行 \(x\) 轮后得到的序列的从位置 \(y\)\(z\) 的大小之和。

\(n,q\le 3\times 10^5\)

做法

考虑对象不同,所得到的结果就不同。

对象1:整体

整体来看,提取有效操作后,每次操作可分为两步:

  • 找出前缀最大值序列的下标 \(\{o_i\}\)

  • \(i\) 从小到大枚举,将第 \(o_i\) 个数放到第 \(o_{i+1}\) 个数之后。

然而这样单次操作数仍是 \(\mathcal O(n^2)\)

对象2:个体

考虑对于每个 \(i\) ,求出第 \(i\) 个数经过 \(x\) 次操作后,变为了第几个数。

打表+分析+结合对象为整体时的性质,第 \(i\) 个数的移动分为两步:

  • 先等前面的最大值移动,然后成为前缀最大值。假设一开始 \(\sum_{j=1}^{i-1}[a_j>a_i]=t\),则要消耗 \(t\) 步。

  • 在剩余的步数中向后跳,应为它及其后面的前缀最大值子序列不变,所以可以看作非前缀最大值元素的相对移动。此时应该找到最远的 \(p\) 使得 \(\sum_{j=i+1}^{p}[a_j>a_i]< x-t\),综合一下就是找到最大的 \(p\) 使得 \(\sum_{j=1}^p[a_j>a_i]<x\)

这可以扫描线+树状数组+堆实现,复杂度 \(\mathcal O(qn\log n)\)

对象3:前缀

把前 \(i\) 个数当作一个整体,其内部也相当于一个冒泡排序,那么进行 \(x\) 轮会将前 \(i\) 个中第 \(1\sim x\) 大值分别送到了第 \(i\sim i-x+1\) 个位置,这时前 \(i-x\) 个位置一定剩下了前 \(i\) 个中较小的 \(i-x\) 个数。

整理一下可以得到性质:进行 \(x\) 轮后,前 \(i\) 个数会变为 \(\min(i+x,len)\) 中的前 \(i\) 小值。

那么询问序列的 \(y\sim z\) 可以看作前 \(z\) 个数减前 \(y-1\) 个数。

主席树实现复杂度 \(\mathcal O((n+q)\log n)\)

posted @ 2025-05-04 15:11  lupengheyyds  阅读(12)  评论(0)    收藏  举报