歸並排序
歸並排序,顧名思義,是一種排序算法。速度應該不錯(由於長期sort我就只知道sort最快[狗頭]),實際上他的思想是分治。
分治分治,分而治之。那么對於一個數的序列怎么去分而治之呢?如果我們面對目前兩個數列:1 2 3 和 4 5 6。將這兩個接在一起形成一個有序的序列,是十分簡單的。直接將它們接在一起就行了。所以說分,是分成兩部分,由於分治的基本思想就是我的子問題先解決再輪到我,所以這兩個序列肯定是有序的。
當然算法主要是解決那些毒瘤情況(而非上文中的超簡單例子)。面對這個:1 4 5和2 3 6。這種例子肯定不是那么好拼的,那么我們分別用兩個指針,一個新的答案數組。這兩個指針分別指向這兩個序列中的數。然后比較,誰小誰先進答案數組,直到完為止。是不是很簡單呢?
逆序對——歸並排序的實際應用
逆序對,是指 i<j且ai>aj這樣的情況。怎么求出逆序對就是歸並排序要做的事情。
對於一個數列,它的逆序對由兩個子序列中的逆序對以及跨子序列的逆序對組成。很顯然,兩個子序列中的答案早以計算好(分治特性)。那么如何求出“跨區間”的逆序對呢?
在歸並排序兩個指針對比的時候,我們可以找到它們之間的大小關系。記兩指針分別為i j 如果 ai<=aj,那么對答案沒有影響。否則的話就意味着逆序對出現。由於子序列滿足有序,所以有i~序列末尾 的數都比aj大,也就是同時出現了多個逆序對,直接加上這么多個答案就行了。
code

void gb(int l,int r){ if(l==r)return; else{ int mid=(l+r)>>1,p=0; gb(l,mid);gb(mid+1,r); int i=l,j=mid+1; while(i<=mid&&j<=r){ if(a[i]<=a[j]){ c[++p]=a[i]; i++; } else{ c[++p]=a[j]; j++; ans+=(mid-i+1); } } while(i<=mid)c[++p]=a[i++]; while(j<=r)c[++p]=a[j++]; for(i=1;i<=p;++i){ a[l+i-1]=c[i]; } } }