最近在看树状数组,看了很长时间,理解的还是很透。
总感觉树状数组很神奇,特别是那段lowbit()函数,简直是妙不可言啊!
为了验证自己看的知识,所以就刷了一道水题,真的是很水的一道题,求逆序数的,在之前,我都是用归并求逆序数的,我记得是0ms通过
今天用了树状数组,也是0ms.
由于树状数组看的不太明白,所以不敢再这多言,怕误导了大家。因为实在是被他的神奇之处所震撼了,短短的十几行代码,就可以完成那么炫酷的事情,真的让人欲罢不能啊!
接下来来我就谈谈我自己的见解,树状之间是通过一个函数完成的,那就是lowbit(),如果你没学过树状数组的话,那接下来的你会惊呆。。下面是lowbit()的源码:
int lowbit(int x) { return x&(-x) ; }
是的,你没有看错,,他就只有一行,但是想要理解这行,可得花费很大的时间。鉴于篇幅,就不在详细赘述了详细请见:<a target=_blank href="http://blog.csdn.net/int64ago/article/details/7429868">点击打开链接</a>。
<pre name="code" class="cpp">index += lowbit(index) //访问父节点 index -= lowbit(index) //访问子节点
这题就是求逆序数的,关于怎么用树状数组求逆序数,且听我解释,,由于题目告知,序列中无重复数字。所以,我们可以转化一下思路,逆序数是指这个数它后面有多少个数比它小的,可以等价为求这个数前面有多少比他大的就行了,由于求比他大的太浪费时间,,所以求比他的小的数量,在转化一下就可以了,具体转化:index-sum(index);其中index为为这个数在序列中位置,sum(index)是指index前面比他小的数的数目之和。
代码:
#include <stdio.h> #include <string.h> #define MAX 1005 int a[MAX] ; int lowbit(int x) { return x&(-x) ; } void update(int pos) { while(pos <= MAX) { a[pos]++ ; pos += lowbit(pos); } } int sum(int pos) { int s = 0 ; while(pos > 0) { s += a[pos] ; pos -= lowbit(pos) ; } return s ; } int main() { int n ; while(~scanf("%d",&n)) { memset(a,0,sizeof(int)*MAX); int pos , s = 0; for(int i = 0 ; i < n ; ++i) { scanf("%d",&pos); update(pos); int t = sum(pos-1) ; s += i-t; } printf("%d\n",s); } return 0 ; }
或者:点击打开链接