逆序对 - 树状数组求解 - 高级数据结构

树状数组是一种非常高级的数据结构,用于求解动态的区间和问题。静态的区间和可以用前缀和用O(n)的时间预处理,再以O(1)的时间单次求解。而树状数组,维护的就是动态的前缀和。也就是说,树状数组可以实现下面两个操作:
1、修改一个数,将一个位置上的数加上一个值
2、求一段数的和
这两个操作的时间复杂度都是O(log2n),而且代码写起来非常简洁,用到了一些二进制的相应思想,比如lowbit(低位技术,求一个数二进制表示中最后一个1以及后面的所有0)。可以说,树状数组几乎是最好的维护区间和的工具。
下面就来步入正题吧。用树状数组如何求解逆序对这一经典问题?我们知道,逆序对的定义是对于序列a,其中所有的不重复的i和j,满足a[i]>a[j]并且i<j。如果直接模拟的复杂度是O(n^2),而一般来说相对好的时间复杂度是O(nlog2n),我们也将要实现这一时间复杂度。

【预备】
首先将序列离散化,将这些数按照原来的大小次序离散成从1到n的整数。比如说[1,5345,23465,24,5666]就将被离散化成[1,3,4,2]。这是一件很简单的事情,只需要一个快速排序或基数排序即可。时间复杂度大概是O(nlog2n)或O(n)。
【树状数组 - 应用】
然后维护一个树状数组,从后往前遍历,比如说现在遍历到第i个元素,这个元素的相应离散化后的值为x,那么我们只需要在[i,n]的区间里找有多少个在区间[1,x-1]的离散化后的相应数字。相应的,因为我们将序列离散化了,所以最多的值不会超过n。所以我们用一种计数排序的思想,在第x个位置加一即可。然后我们如果要查找已经出现的[1,x-1]的数字的总数,那我们就可以直接求[1,x-1]区间的前缀和即可,一个操作是O(log2n),并将返回的结果加入到逆序对的个数总和之中。接着进行完这个操作之后,我们就可以将第x个位置的数加上1。最后,直接将逆序对的个数总和输出即可,这就是答案。
【总结】
其实用树状数组求逆序对的这个过程还是非常简单的,精髓其实就是那个计数排序!首先按大小离散化(离散化还有一个目的,那就是将整个树状数组的大小占用大大减少,不然的话如果输入是10^18的数,不离散化就绝对做不了了),接着用相应的计数排序思想求前缀和就可以了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值