练习题 POJ2299的两种解法 树状数组/归并排序
Poj 2299 统计如果要对一串数据排序,冒泡排序需要交换多少次
即求逆序数,可以用树状数组或者归并排序求取。
1 //Poj 2299 树状数组解法 2 #include <stdio.h> 3 const int N = 500005; 4 struct Node{ 5 int val; 6 int pos; 7 } pool[N]; 8 int c[N], reflect[N], n; 9 10 int lowbit(int x){ 11 return x & (-x); 12 } 13 void update(int x){ 14 while (x <= n){ 15 c[x] += 1; 16 x += lowbit(x); 17 } 18 } 19 int getsum(int x){ 20 int sum = 0; 21 while (x > 0){ 22 sum += c[x]; 23 x -= lowbit(x); 24 } 25 return sum; 26 } 27 int main(){ 28 while (scanf("%d", &n) != EOF && n){ 29 for (int i = 1; i <= n; ++i){ 30 scanf("%d", &pool[i].val); 31 pool[i].pos = i; 32 } 33 qsort(1, n); //排序 34 for (int i = 1; i <= n; ++i) reflect[pool[i].pos] = i; //离散化 35 for (int i = 1; i <= n; ++i) c[i] = 0; //初始化树状数组 36 long long ans = 0; 37 for (int i = 1; i <= n; ++i){ 38 update(reflect[i]); 39 ans += i - getsum(reflect[i]); 40 } 41 printf("%lld\n", ans); 42 } 43 return 0; 44 } 45 void qsort(int s, int t){ 46 int l = s, r = t; 47 Node tmp = pool[s]; 48 pool[s] = pool[l]; 49 while (true){ 50 while ((r > l) && (pool[r].val >= tmp.val))--r; 51 if (r <= l)break; //再也找不到比tmp小的数 52 pool[l] = pool[r]; 53 while ((l < r) && (pool[l].val <= tmp.val))++l; 54 if (l >= r)break; 55 pool[r] = pool[l]; 56 } 57 pool[l] = tmp; 58 if (s < --l)qsort(s, l); 59 if (t > ++r)qsort(r, t); 60 }
/*POJ 2299 归并排序解法
求逆序对的数目可以使用归并排序,其实逆序对的数目是归并排序的一个附属产品,只是在归并排序的过程中顺便算出来的。
(2路)归并排序的思想:先把每个数看成一段,然后两两合并成一个较大的有序数组,再把较大的两两合并,直到最后成为一个有序数组。例如:
初始数组为:4 2 1 3
先把每个数看成一段,即:4 | 2 | 1 | 3
接着两两合并成有序数组,即:2 4 | 1 3
最后合并成总的有序数组,即:1 2 3 4
*/
1 #include <stdio.h> 2 long long num[500005]; 3 long long temp[500005]; 4 int n; 5 long long ans; 6 7 void merge(int low, int mid, int high){ 8 int i = low, j = mid + 1, k = low; 9 while (i <= mid && j <= high){ 10 if (num[i] <= num[j]){ 11 temp[k++] = num[i++]; 12 } 13 else{ 14 ans += j - k; //统计逆序,需要交换的次数 15 temp[k++] = num[j++]; 16 } 17 } 18 while (i <= mid) temp[k++] = num[i++]; 19 while (j <= high) temp[k++] = num[j++]; 20 for (i = low; i <= high; ++i){ 21 num[i] = temp[i]; 22 } 23 } 24 void mergeSort(int a, int b){ 25 if (a < b){ 26 int mid = (a + b) / 2; 27 mergeSort(a, mid); 28 mergeSort(mid + 1, b); 29 merge(a, mid, b); 30 } 31 } 32 33 int main(){ 34 while (scanf("%d", &n) != EOF && n > 0){ 35 ans = 0; 36 for (int i = 0; i < n; ++i) 37 scanf("%lld", num + i); 38 mergeSort(0, n - 1); 39 printf("%lld\n", ans); 40 } 41 return 0; 42 }