并归排序
归并操作(merge),也叫归并算法,指的是将两个顺序序列合并成一个顺序序列的方法。
如 设有数列{6,202,100,301,38,8,1}
初始状态:6,202,100,301,38,8,1
第一次归并后:{6,202},{100,301},{8,38},{1},比较次数:3;
第二次归并后:{6,100,202,301},{1,8,38},比较次数:4;
第三次归并后:{1,6,8,38,100,202,301},比较次数:4;
总的比较次数为:3+4+4=11;
逆序数为14;
时间复杂度:nlog(n);
例题:P1908 逆序对
题目描述
猫猫TOM和小老鼠JERRY最近又较量上了,但是毕竟都是成年人,他们已经不喜欢再玩那种你追我赶的游戏,现在他们喜欢玩统计。最近,TOM老猫查阅到一个人类称之为“逆序对”的东西,这东西是这样定义的:对于给定的一段正整数序列,逆序对就是序列中ai>aj且i<j的有序对。知道这概念后,他们就比赛谁先算出给定的一段正整数序列中逆序对的数目。
Update:数据已加强。
输入输出格式
输入格式:
第一行,一个数n,表示序列中有n个数。
第二行n个数,表示给定的序列。序列中每个数字不超过10^9。
输出格式:
给定序列中逆序对的数目。
输入输出样例
输入样例#1:
6
5 4 2 6 3 1
输出样例#1:
11
说明:
对于所有数据,n≤5×10 ^5。
代码:
#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio>
using namespace std;
long long int n;
long long int qq[500050],r[500050],ans=0;
void msort(long long int s,long long int t)
{
long long int i,k,mid,j;
if(s==t) return;
mid=(s+t)/2;
msort(s,mid);
msort(mid+1,t);//→→→→→→→递归的体现
i=s;j=mid+1;k=s;
while(i<=mid&&j<=t)
{
if(qq[i]<=qq[j]) r[k++]=qq[i++];
else// 出现逆序对
{
ans=ans+mid-i+1;//加上大于qq[j]所产生的逆序对
r[k++]=qq[j++];
}
}
for(;i<=mid;i++) r[k++]=qq[i];
for(;j<=t;j++) r[k++]=qq[j];
for(i=s;i<=t;i++)//复制回a数组中
qq[i]=r[i];
}
int main()
{
long long int i;
scanf("%lld",&n);
for(i=1;i<=n;i++)
scanf("%lld",&qq[i]);
msort(1,n);//从1到n将a数组排序;
printf("%lld\n",ans);
return 0;
}