POJ - 2299 - Ultra-QuickSort(归并排序求逆序数)
题目链接
题目大意:给你一串数让你求他们冒泡排序的总交换次数。
假设我们要让一串数从小到大排序,那么对于其中的一个数\(ai\),它前面有多少个大于它的数,那么它需要交换的次数就是多少,换句话说,就是求逆序数。归并排序求逆序数就是在归并排序的基础上加入一行代码来统计排序过程中一个数从原来的位置到现在的位置需要移动的位数。至于为什么是\(mid-l+1\),每次归并时,如果要让右半边的数中的一个放到左半边剩余的数前面,就相当于把左半边每个数右移一位,就相当于和相邻的数交换了\(mid-l+1\)次。
const int maxn = 5e5+10;
int arr[maxn], temp[maxn], n;
ll ans;
void unite(int l, int r) {
if (l>=r) return;
int mid = (l+r)>>1;
unite(l, mid);
unite(mid+1, r);
int l1 = l, l2 = mid+1;
for (int i = l; i<=r; ++i) {
if (l2>r || (l1<=mid && arr[l1]<=arr[l2]))
temp[i] = arr[l1++];
else {
temp[i] = arr[l2++];
ans += (ll)mid-l1+1;
}
}
for (int i = l; i<=r; ++i)
arr[i] = temp[i];
}
int main(void) {
while(~scanf("%d", &n) && n) {
ans = 0;
for (int i = 0; i<n; ++i)
scanf("%d", &arr[i]);
unite(0, n-1);
printf("%lld\n", ans);
}
return 0;
}