本文比较 树状数组,线段树,还有一种unnamed的树状结构,在求逆序数中的运行效率。
给定数组a,如果有i, j, i < j且a[i] > a[j],我们称之为一个逆序(反序),求逆序数即找出这样的i,j对的数目。如果通过交换相邻元素来对数组排序,那么逆序数正好是最少的交换次数。长度为n的排列,其逆序数的期望是n(n-1)/4,方差是n(2n+5)(n-1)/72。逆序数的平均数可以大概视为n^2/4,标准差大概视为(1/6)n^(3/2)。
经典的求逆序数的算法可以由归并排序给出,但是在实现细节上可能会出错。而使用辅助数据结构则使得实现难度降低。
最简单的是用线段树:从左往右扫描,每扫描到一个数时,则通过线段树求出当前线段树上大于当前元素的元素的个数。然后将当前元素加到线段树中。
在这里,上述算法也可以用树状数组(binary index tree)来实现。在添加元素时,从大到小,可以理解为从最小元素到当前元素添加了一根线段。在查询时,从小到大累加,可以理解为求当前元素被多少个线段覆盖,也就是比当前元素大的元素的数量。
还有一种树状结构,对于[l, r]的一个区间,令mid=l+r>>1用tree[mid]来维护[mid, r]上的元素个数。
插入时,如果需要插入的元素正好是mid,则计数加1,算法结束。
如果在[mid+1, r]上,则计数加1,同时递归到右区间:l = mid + 1。
如果在[l, mid-1]上,则tree[
给定数组a,如果有i, j, i < j且a[i] > a[j],我们称之为一个逆序(反序),求逆序数即找出这样的i,j对的数目。如果通过交换相邻元素来对数组排序,那么逆序数正好是最少的交换次数。长度为n的排列,其逆序数的期望是n(n-1)/4,方差是n(2n+5)(n-1)/72。逆序数的平均数可以大概视为n^2/4,标准差大概视为(1/6)n^(3/2)。
经典的求逆序数的算法可以由归并排序给出,但是在实现细节上可能会出错。而使用辅助数据结构则使得实现难度降低。
最简单的是用线段树:从左往右扫描,每扫描到一个数时,则通过线段树求出当前线段树上大于当前元素的元素的个数。然后将当前元素加到线段树中。
在这里,上述算法也可以用树状数组(binary index tree)来实现。在添加元素时,从大到小,可以理解为从最小元素到当前元素添加了一根线段。在查询时,从小到大累加,可以理解为求当前元素被多少个线段覆盖,也就是比当前元素大的元素的数量。
还有一种树状结构,对于[l, r]的一个区间,令mid=l+r>>1用tree[mid]来维护[mid, r]上的元素个数。
插入时,如果需要插入的元素正好是mid,则计数加1,算法结束。
如果在[mid+1, r]上,则计数加1,同时递归到右区间:l = mid + 1。
如果在[l, mid-1]上,则tree[