归并排序,简而言之就是将两个内部顺序已经确定的集合进行合并,使得合并后的集合仍然有序
那么对于一个无序集合,就需将其递归到最底层从底开始回归上一层,这样不停地将每个集合内部归并而有序。
那么对于一个集合的逆序对该如何求呢?
比如集合{5,4,3,2,1}逆序对为4+3+2+1 = 10
那么对于归并排序的求解过程:
第一层:
1.1:5 4 3
1.2:2 1
第二层:
2.1.1: 5 4
2.1.2: 3
2.2.1: 2
2.2.2: 1
第三层:
3.1.1.1 :5
3.1.1.2 :4
3.1.2: 3
3.2.1: 2
3.2.2: 1
第三层归并后:
4 5
3
2
1
第二层归并后
3 4 5
1 2
第一层归并后
1 2 3 4 5
那么对于逆序对的求解:
每一层的求解的是该层被归并的两个集合存在的逆序对数量
那么由于该层的两个集合已经内部有序了,故如果存在
(mid + 1, r)集合中第i个元素,比(l, mid)集合中的第j个元素小,那么答案加上(mid - j + 1)即可
归并模板:
void merge_sort(int q[], int l, int r){
if(l >= r) return ;
int mid = l + r >> 1;
merge_sort(q, l, mid), merge_sort(q, mid + 1, r);
int i = l, j = mid + 1, k = 0;
while(i <= mid && j <= r){
if(q[i] <= q[j]) t[k++] = q[i++];
else t[k++] = q[j++];
}
while(i <= mid) t[k++] = q[i++];
while(j <= r) t[k++] = q[j++];
for(i = l, j = 0; i <= r; i++, j++) q[i] = t[j];
}
Acwing788 求逆序对:
ACcode:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 100010;
int q[N], t[N];
int n;
ll ans = 0;
void merge_sort(int q[], int l, int r){
if(l >= r) return ;
int mid = l + r >> 1;
merge_sort(q, l, mid);
merge_sort(q, mid + 1, r);
int i = l, j = mid + 1, k = 0;
while(i <= mid && j <= r){
if(q[i] > q[j]){
ans += (mid - i + 1);
t[k++] = q[j++];
}
else t[k++] = q[i++];
}
while(i <= mid) t[k++] = q[i++];
while(j <= r) t[k++] = q[j++];
for(i = l, j = 0; i <= r; i++, j++) q[i] = t[j];
}
int main()
{
scanf("%d", &n);
for(int i = 1; i <= n; i++) scanf("%d", &q[i]);
merge_sort(q, 1, n);
printf("%lld\n", ans);
return 0;
}