题目解析
题干信息很简单,看到数据量之后就不简单了。在数据量小的时候可以使用双层循环暴力的方法来求答案。显然对于这道题而言 O(n2)O(n^2)O(n2) 是完全过不去的。
前置知识:
1. 使用树状数组求逆序对。
2. 会归并排序等分治算法。
考虑使用分治算法来解决,这是一道经典的三维偏序问题。对于这种坐标相关题目,一个很常见的方法是先对其中一个纬度进行排序。这样子控制一个纬度之后再去查找速度就会快很多。
例如如果控制语文成绩这个维度,按照从大到小的顺序排序后可以得出以下结论:
第 iii 位同学的嫉妒值一定只会被前 i−1i-1i−1 位同学所影响,排在 iii 后面的所有学生都不会贡献为第 iii 为同学贡献嫉妒值。
接下来的做法和分治逆序对很像,每次将所有的数字分成两半,以任意一个 kkk 为分界线,保证第 kkk 个学生的语文成绩低于第 k+1k+1k+1 个学生的成绩即可。直至区间的长度为 111。
由于前半部分的任意 xxx 肯定比后半部分的任意 xxx 要大,可以按照数学成绩再分别被前半部分和后半部分的学生进行排序。这样子依然也不会损失单调性,只要保证前半部分 xxx 都比后半部分 xxx 大即可。接下来我们就可以遍历后半部分,在遍历的时候计算单个点所获得的贡献(这些贡献来自于前半部分维度)。
截至目前已经对两个维度进行排序了,最后一个维度可以使用树状数组进行维护。这部分可以借用树状数组求逆序对的思想(请自行查阅,类似于本场比赛的第四题 - 股票购买方案)。
AC代码
复杂度分析
时间复杂度也比较好计算,分治的时间复杂度为 O(logn×n)O(\log{n} \times n)O(logn×n)。树状数组的单点修改和区间查询也分别是 O(logn)O(\log{n})O(logn) 级别的。综合下来时间复杂度在 O(n×log2n)O(n \times \log^2{n})O(n×log2n) 附近。因为题输入数据比较大,注意常数优化。