研究对象的启示——排序问题 题解
排序问题 题解
题目描述
你有 \(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)\)。

 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号