归并和逆序对

逆序对: 对于一个数组a,若i<j,且a[i]>a[j],则称a[i]与a[j]构成逆序对;

归并排序:
划分问题:把序列尽量分成二个相等的二部分
递归求解:把二半元素分别排序
合并问题:把二个有序表合成一个表

求逆序对:由于合并操作是从小到大进行的,当右边一段复制到b数组里面时,左边还没有来得及复制到b数组
的哪些数就是比a[j]大的数,答案加上(r1-l1+1)即可,即;就是把归并排序模板判断(a[l1]<a[l2])(注意等号)加上ans+=r1-l1+1;

代码:

#include<stdio.h>
int a[500005],b[500005];
long long ans;
void mergesort(int l,int r)
{
if(l>=r)return ;
int mid=(l+r)/2;//划分
mergesort(l,mid);//递归求解
mergesort(mid+1,r);//递归求解
int l1=l,r1=mid,l2=mid+1,r2=r;
int tot=0;
while(l1<=r1&&l2<=r2)//合并
{
if(a[l1]<=a[l2])b[++tot]=a[l1++];
else b[++tot]=a[l2++],ans+=r1-l1+1;
}
while(l1<=r1)b[++tot]=a[l1++];//这二种情况只会
while(l2<=r2)b[++tot]=a[l2++];//出现1种情况,想想为什么
for(int i=tot,j=r2;i>=1;–i,–j)//将辅助空间b数组复制到a数组
a[j]=b[i];
}
int main()
{
int n;
while(scanf("%d",&n)&&n)
{
ans=0;//注意更新
for(int i=1;i<=n;++i)scanf("%d",&a[i]);
mergesort(1,n);
printf("%lld\n",ans);
}
}

猜你喜欢

转载自blog.csdn.net/weixin_43871956/article/details/88822891