本文对题解中算法二进行了实现。此算法和标准归并排序对比,只是多了一条语句,复杂度nlogn满足要求。
在归并排序过程中,当每次做到左半段和右半段合并时,如果左半段的a[i]大于右半段的a[j],那么左半段i之后元素也必然都大于a[j],同时左半段任一元素,其原下标 一定小于右半段任一元素。这样就可以说a[i].......a[mid]>a[j],那么他们都和a[j]形成逆序对。
#include <iostream>
typedef long long ll;
using namespace std;
int n,a[100005],t[100005],ans=0;
void merg(int l,int r)
{
if(l>=r) /**< 结束条件 */
return;
int mid=(l+r)/2;
merg(l,mid),merg(mid+1,r);/**< 求中点,二分 */
int i=l,j=mid+1,k=l;
while(i<=mid&&j<=r)/**< 左右两端归并 */
{/**<a[i]>a[j]时,从a[i].....a[mid]必然都大于a[j],这些元素在左半段,其位置小于j,总数为mid-i+1 */
if(a[i]>a[j])
ans+=mid-i+1,t[k++]=a[j++];
else
t[k++]=a[i++];
}
while(i<=mid) /**< 假如左半段有剩余 */
t[k++]=a[i++];
while(j<=r)/**< 假如右半段有剩余 */
t[k++]=a[j++];
for(i=l;i<=r;i++) /**< 归并之后复制回原数组a */
a[i]=t[i];
}
int main()
{
ios::sync_with_stdio(0),cin.tie(0);
int i,j;
cin>>n;
for(i=1;i<=n;i++)
cin>>a[i];
merg(1,n);
cout<<ans;
return 0;
}