归并排序
本质上就是不断迭代,将两段有序的数列合并,复杂度和快速排序一样,都是nlogn。
归并排序求逆序对
在两个有序数列l -> mid和mid+1 -> r里,如果左边的第i个数大于右边的第j个数,就代表左边第i个数后面的数,即mid-i+1个数都是大于右边的第j个数,即贡献了mid-i+1个逆序对,累加到答案就行,因为是不断迭代上来的,所以并不需要分别求两个区间内的逆序对。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5;
int q[N + 5],tmp[N + 5];
ll merge_sort(int l,int r){
if(l == r) return 0;
int mid = l + r >> 1;
ll ans = merge_sort(l,mid) + merge_sort(mid + 1,r);
int k = 0,i = l,j = mid + 1;
while(i <= mid && j <= r){
if(q[i] <= q[j]){
tmp[++ k] = q[i ++];
}else{
tmp[++ k] = q[j ++];
ans += mid - i + 1;
}
}
while(i <= mid) tmp[++ k] = q[i ++];
while(j <= r) tmp[++ k] = q[j ++];
for(i = l,j = 1;i <= r;i ++,j ++) q[i] = tmp[j];
return ans;
}
int main(){
int n;
cin >> n;
for(int i = 1;i <= n;i ++)
scanf("%d",&q[i]);
cout << merge_sort(1,n);
/* for(int i = 1;i <= n;i ++)
cout << q[i];*/
return 0;
}