前言
看网上都说这个题目很经典,但是自己最初根本没办法将区间求和与求逆序对联系起来,思考了许久,此处进行记录并方便后来着理解。
注:本文的讲解建议配合线段树之逆序对问题代码来看。
题目
逆序对
在一个序列中,如果 且,且称和是一个逆序对,然后求该nums序列中逆序对的个数。
分析如下
先不考虑离散化,离散化仅仅是缩小线段树的大小以及减少随之产生的查询次数,我们直接将离散后的pos当做原先说明的nums序列。
我们按照顺序迭代序列,此时在线段树中插入当前数字(见代码第3行),随后便查询(pos[i] + 1, len + 1)的序列sum(见代码第7行)。
为什么查询(pos[i] + 1, len + 1)的序列sum呢?因为此时** (pos[i] + 1, len + 1)的序列sum值 是在之前已经进行插入的,且(pos[i] + 1, len + 1)保证了这里面的值肯定是大于当前的。
即(pos[i] + 1, len + 1)的序列sum值**满足两个条件:
- 出现的数字所对应的下标小于;
- 且当前所有的值;
这样一思考意味着什么?即我们将当前插入是为了后面判断是否有大于判断时所对应的数值,而query是为了统计大于的数值的个数。
换句话说就是,把理解为就好了,此时的理解为定义的。
注:这样就将一个统计大于对应的关系转换为一个区间查询的问题。
扩展思考
此处我们是以去进行思考的,我们能不能从的角度去思考,也就是统计其序列右侧小于它元素的个数?
答案肯定是可以的,考虑时效性。
也就是我们需要逆序遍历(为了让右边的数先都出现,并在线段树中进行标记嘛)
还有查询的是(因为我们要找比当前更小的数嘛)
逆序对扩展
在数列中只要有,且,那么就称这是一个“好的”组合,给出任意个这个组合,求解“好的”组合的个数。
思路与逆序对一样,建树统计的代码也和逆序对的一样,区别在于统计方法上。
分析如下
通过对逆序对扩展思考的理解,我们可以明白。逆序对扩展我们可以理解为统计序列中左侧小于其自身的数的个数,以及右侧大于其自身数的个数。
结合代码我们可以看出:
逆序时统计的是,则意味着求的是,且这一段,找到所有数右侧大于它的部分,即。
正序时统计的是,则意味着求的是且这一段,找到所有数左侧小于它的部分,即。
然后结合这两个就可以了。
参考
后记
笔者理解了很久,可能描述不是很清晰,可以随时来扰进行交流探讨。