逆序对
逆序对是啥呢?
就是说有一个数组:3,1,4,5,2
然后逆序可以理解为默认升续,但是数对(两个)是降序排列,和升序相反,所以叫逆序。
我们的目的是求数目QWQ数目QW数目QWQ不是他长啥样
我查到的有三种,一种是暴力枚举来找逆序对时间复杂度n方,我们今天就讲这个(唔)。
一种是利用并归排序来找逆序对数量,这个我不会(唔)。
最后一种是利用树状数组求逆序对,所以我们不讲这个。
恩,我感觉我讲完了可以收尾了(~ ̄▽ ̄)~。。。
好,那么正题,我们主要讲树状数组的逆序对,对于暴力太简单,对于并轨我不会QWQ。
那么我们先来看看上边的数组3,1,4,5,2,我们我要找的他逆序对怎么办呢
小A(举手)我们从第一个数开始向最后一个数枚举就好了,找完一个找下一个。
(凳子糊上去),好了,我们继续。
那么树状数组怎么做呢?
首先,我们要对数据排序:确认是大的在前小的在后(为什么呢,不解释)
这样我们就可以每次都用O(1)的时间完成取数的过程。然后将取来的数放入c数组中,位置放在他本来的排列位置。
然后我们先将最大的数5放进去,放入对应的位置并标记为1表示这里有一个数了,同时(这里是重点重点重点!!!!!),我们要检测一下他前面有没有已经进入c数组的数,如果有,那么我们就找到一个逆序对了:
然后再把第二大的数放进去,然后还是要找:
经过一直坚持不懈的找,我们终于找到了这样一个数:
当我们把2放入时,这时候前边终于有数了,那么前边有几个数我们答案加几,所以答案加3,我们找到三个逆序对。
当我们找完时应该是这样的,这时候最后一个数也找完了,又找到一个逆序对,所以答案再加1;最终的答案就是4了。
看了这么多你一定想说,那树状数组有什么用呢QWQ,其实树状数组的用处就在这,他的主要用途就是求前边到底有几个1的如果你不知道啥是树状数组,戳这里http://www.cnblogs.com/fuyun-boy/p/5913438.html
所以过程很简单,代码也很简单:
1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 //==================================================== 5 struct NODE{ //计数和数本来位置的函数 6 int first,second; 7 }a[500]; 8 //==================================================== 9 int c[500],N,ans=0; 10 //==================================================== 11 bool cmp(NODE a,NODE b) //比较函数,确认大的在前 12 { 13 return a.first>=b.first?true:false; 14 } 15 //==================================================== 16 void ADD(int x,int y) 17 { 18 for(int i=x;i<=N;i+=i&(-i)){ 19 c[i]+=y; 20 } 21 } 22 //==================================================== 23 int sum(int x) 24 { 25 int SUM=0; 26 for(int i=x;i>=1;i-=i&(-i)){ 27 SUM+=c[i]; 28 } 29 return SUM; 30 } 31 //==================================================== 32 void init() 33 { 34 int k; 35 cin>>N; 36 for(int i=1;i<=N;i++){ //输入n个数 37 cin>>a[i].first; //数的本体 38 a[i].second=i; //数的位置,因为一会要放入c数组 39 } 40 sort(a+1,a+1+N,cmp); //排序,为了取数方便 41 } 42 //==================================================== 43 void work() 44 { 45 for(int i=1;i<=N;i++){ //对N个数放入c数组并且计算是否前边有数 46 ans+=sum(a[i].second); //树状数组添加 47 ADD( a[i].second, 1 ); //树状数组求前边所以数的和 48 } 49 } 50 //==================================================== 51 int main() 52 { 53 init(); //初始化 54 work(); //计算 55 cout<<ans; //输出答案 56 system("pause"); 57 return 0; 58 }