求逆序对数有多种方法,如归并排序法、线段树 \ 树状数组法、离散化。
归并排序法几乎就是归并排序。
白书讲解


紫书代码
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 
 | int A[MAXN]= {3, 6, 2, 1, 4, 5, 13, 7, 12, 10}, T[MAXN];
 int merge_cnt(int l, int r)
 {
 int cnt = 0;
 
 if(r - l > 1)
 {
 int mid = l+r>>1;
 cnt += merge_cnt(l, mid);
 cnt += merge_cnt(mid, r);
 
 int p=l, q=mid, i=l;
 while(p<mid || q<r)
 {
 if(q>=r || (p<mid && A[p]<=A[q]))
 {
 T[i++] = A[p++];
 }
 else
 {
 T[i++] = A[q++];
 cnt += mid - p;
 }
 }
 
 for(i=l; i<r; i++)
 A[i] = T[i];
 }
 
 return cnt;
 
 }
 
 | 
白书代码
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 
 | int merge_count(vector<int> &a){
 int n = a.size();
 if(n<=1)
 return 0;
 
 int cnt = 0;
 vector<int> b(a.begin(), a.begin()+n/2);
 vector<int> c(a.begin()+n/2, a.end());
 
 cnt += merge_count(b);
 cnt += merge_count(c);
 
 int ai=0, bi=0, ci=0;
 while(ai < n)
 {
 if(bi < b.size() && (ci==c.size() || b[bi]<=c[ci]) )
 {
 a[ai++] = b[bi++];
 }
 else
 {
 cnt += n/2-bi;
 a[ai++] = c[ci++];
 }
 
 }
 
 return cnt;
 }
 
 | 
一点建议
敲完数组实现的紫书代码和白书的 vector 实现的代码, 第一反应就是每次对 vector 的构造及初始化应该会费时间,于是测试了下。果不其然,在 $10^6$ 数据量下, 代码运行效果如图: (突然发现当时复制的代码没改过来,第三行应为紫书代码,QAQ)
(突然发现当时复制的代码没改过来,第三行应为紫书代码,QAQ)
经过多次实验,用时稳定在本次用时左右。可以看出,用数组实现的效率远远高于 vector 实现。故推荐数组实现。