逆序数 POJ 2299 Ultra-QuickSort

题目传送门

 1 /*
 2     题意:就是要求冒泡排序的交换次数。
 3     逆序数:在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序。
 4     一个排列中逆序的总数就称为这个排列的逆序数。逆序数为偶数的排列称为偶排列;逆序数为奇数的排列称为奇排列。
 5     如2431中,21,43,41,31是逆序,逆序数是4,为偶排列。也是就说,对于n个不同的元素,
 6     先规定各元素之间有一个标准次序(例如n个 不同的自然数,可规定从小到大为标准次序),于是在这n个元素的任一排列中,
 7     当某两个元素的先后次序与标准次序不同时,就说有1个逆序。一个排列中所有逆序总数叫做这个排列的逆序数。
 8 
 9     接下来有多种做法求解逆序数:1. 暴力;2. 归并排序;3. 线段树-单点更新;4. 树状数组
10 */
 1 /*
 2     暴力 超时 O(n^2)
 3 */
 4 #include <stdio.h>
 5 
 6 const int MAX_N = 500000;
 7 int a[MAX_N+10];
 8 long long cnt = 0;
 9 
10 int main(void)        //POJ 2299 Ultra-QuickSort
11 {
12     //freopen ("inD.txt", "r", stdin);
13     int n;
14     
15     while (scanf ("%d", &n) != EOF && n)
16     {
17         for (int i=1; i<=n; ++i)
18         {
19             scanf ("%d", &a[i]);
20         }
21 
22         for (int i=1; i<=n; ++i)
23         {
24             for (int j=i+1; j<=n; ++j)
25             {
26                 if (a[i] > a[j])
27                     cnt++;
28             }
29         }
30         printf ("%lld
", cnt);
31         cnt = 0;
32     }
33     
34     return 0;
35 }
暴力 超时 O(n^2)
 1 /* 
 2     归并排序是将数列a[p, r]分成两半a[p, q]和a[q+1,r]分别进行归并排序,
 3     然后再将这两半合并起来。在合并的过程中(设p<=i<=q,q+1<=j<=r),
 4     当L[i]<=R[j]时,并不产生逆序数;
 5     当L[i]>R[j]时,在前半部分中比L[i]大的数都比R[j]大,
 6     将R[j]放在L[i]前面的话,逆序数要加上q+1-i。
 7     因此,可以在归并排序中的合并过程中计算逆序数。 
 8  
 9     这道题充分印证了,即使merge本身可能用的不多,但分冶的思想却是无所不在:)
10 */
11 #include <stdio.h>
12 
13 const int MAX_N = 500000;
14 const int INF = 0xffffff;
15 int a[MAX_N+10];
16 long long cnt = 0;
17  
18 void Merge(int *a, int p, int q, int r)
19 {
20     int n1 = q - p + 1;
21     int n2 = r - q;
22     int L[MAX_N/2+1], R[MAX_N/2+1];
23     int i, j;
24     for (i=1; i<=n1; ++i)    L[i] = a[p+i-1];
25     for (j=1; j<=n2; ++j)    R[j] = a[q+j];
26     L[n1+1] = INF;    R[n2+1] = INF;
27 
28     i = 1;    j = 1;
29     for (int k=p; k<=r; ++k)
30     {
31         if (L[i] <= R[j])
32         {
33             a[k] = L[i++];
34         }
35         else
36         {
37             a[k] = R[j++];
38             cnt += n1 - i + 1;         //此步骤是在归并排序法中加的一句,用来计数求逆序数的数目
39         }
40     }
41 }
42 
43 void MergeSort(int *a, int p, int r)
44 {
45     int q;
46     if (p < r)
47     {
48         q = (p + r) / 2;
49         MergeSort (a, p, q);
50         MergeSort (a, q+1, r);
51         Merge (a, p, q, r);
52     }
53 }
54 
55 int main(void)        //POJ 2299 Ultra-QuickSort
56 {
57     //freopen ("inD.txt", "r", stdin);
58     int n;
59     
60     while (scanf ("%d", &n) != EOF && n)
61     {
62         for (int i=1; i<=n; ++i)
63         {
64             scanf ("%d", &a[i]);
65         }
66         MergeSort (a, 1, n);
67         printf ("%lld
", cnt);
68         cnt = 0;
69     }
70     
71     return 0;
72 }
归并排序
 1 /*
 2     线段树-单点更新
 3 */
 4 #include <cstdio>
 5 #include <algorithm>
 6 #define lson l, m, rt << 1
 7 #define rson m+1, r, rt << 1 | 1
 8 using namespace std;
 9 
10 const int MAX_N = 500000;
11 const int INF = 0x3f3f3f3f;
12 int a[MAX_N];
13 int b[MAX_N];
14 int sum[MAX_N << 2];
15 
16 void pushup(int rt)
17 {
18     sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
19 }
20 
21 void build(int l, int r, int rt)
22 {
23     sum[rt] = 0;
24     if (l == r) return ;
25     int m = (l + r) >> 1;
26     build (lson);
27     build (rson);
28 
29     pushup (rt);
30 }
31 
32 void update(int p, int l, int r, int rt)
33 {
34     if (l == r)
35     {
36         sum[rt]++;      //记录次数
37         return ;
38     }
39     int m = (l + r) >> 1;
40     if (p <= m)
41     {
42         update (p, lson);
43     }
44     else
45         update(p, rson);
46     pushup (rt);
47 }
48 
49 int query(int ql, int qr, int l, int r, int rt)
50 {
51     if (ql <= l && r <= qr)
52     {
53         return sum[rt];
54     }
55     int m = (l + r) >> 1;
56     int ans = 0;
57     if (ql <= m)    ans += query (ql, qr, lson);
58     if (qr > m)     ans += query (ql, qr, rson);
59 
60     return ans;
61 }
62 
63 int BinarySearch(int key, int l, int r)
64 {
65     while (r >= l)
66     {
67         int mid = (l + r) >> 1;
68         if (key == b[mid])    return mid;
69         if (key < b[mid])    r = mid - 1;
70         else    l = mid + 1;
71     }
72 }
73 
74 int main(void)
75 {
76     //freopen ("inD.txt", "r", stdin);
77     int n;
78     while (~scanf ("%d", &n) && n)
79     {
80         build (0, n-1, 1);
81         
82         for (int i=1; i<=n; ++i)   
83         {
84             scanf ("%d", &a[i]);
85             b[i] = a[i];
86         }
87         sort (b+1, b+n+1);
88         long long ans = 0;
89         for (int i=1; i<=n; ++i)
90         {
91             int x = BinarySearch (a[i], 1, n);
92             ans += query (x, n, 1, n, 1);
93             update (x, 1, n, 1);
94         }
95         printf ("%lld
", ans);
96     }
97 
98     return 0;
99 }
线段树-单点更新
编译人生,运行世界!
原文地址:https://www.cnblogs.com/Running-Time/p/4392008.html