【前言】
好吧,我承认这个是完全抄袭过来的。而且我还没付诸实践的。
之前写过一个归并排序求解逆序数对的:http://blog.youkuaiyun.com/Human_CK/archive/2011/03/11/6239453.aspx。
不过我看了http://blog.foreverzeus.com/?p=853之后觉得用树状数组其实可能更简单更容易理解或许还会更快。
【思路】
假设有1到n的数任意排列,要求其逆序数对。
5 2 1 3 4
首先初始化树状数组为0。
把5放进去,把5进行加1操作。并计算sum[5]。此时数组为0 0 0 0 1。
对于第i个数,包括其本身最多会产生i个逆序数对。由于此时数组保存的是之前所有的数,我们可以计算出此时比当前数小的数的个数,在这里这个个数为1(包括5本身),说明在这之前有1个数比它小(即不能构成逆序数对),再用i-sum[5](此时i=1,sum[5]=1)=0得到此时逆序数对为0。
对于第二个数,加1并计算得到0 1 0 0 1。
sum[2] = 1,i-sum[2](此时i=2,sum[2]=1)=1,说明此时有1个逆序数(5是2的逆序数)。
当i=3时,得到1 1 0 0 1,i-sum[1](i=3,sum[1]=1)=2,说明有两个逆序数。
以此类推。
我觉得这个思路还是很简单的,代码写起来也很容易,因为树状数组本身的代码就很简单。
而对于不连续的数字,可以先将其离散化。
比如将 9 1 0 5 4 离散为 5 2 1 3 4。即每个数对应为其在这个数列中的排名。
【代码】
ans[]用于记录离散后的数值。
add()用于更新节点。
calsum()为计算树状数组到某个点的总和。
cnt用于记录总逆序数对个数。
【P.S】
其实我是在找怎样用树状数组“更新区域查询节点”的……
谁知道找了零零散散的一些,没有完整的比较好理解的思路……
然后就在无意中看到了这个,也算是一个收获吧!
继续征程。