逆序对

仔细想想,如果存在正整数 i, j 使得 1 ≤ i < j ≤ n  A[i] > A[j],则称为一个逆序对 这就意味着如果想要统计逆序对,就要在数列中 从左向右依次算出 每个数右侧自己小的数个数,最后将将其相加。但是,当我们新读入一个数时,根本不清楚后面还未读进来的数是怎样的!

所以对于此类问题,有两种解决方案:

  1. 从右向左读取 统计已经读取的数中比自己小的个数。
  2. 从左向右读取 统计已经读取的数中比自己大的个数。

根据树状数组向上更新、向下查询的特性,我们更习惯用从右到左向上查询的方法。(其实从左到右向上查询也不是无法实现,只要求出顺序对个数 再用组合总数N*(N-1)/2减掉顺序对个数同样可以得到逆序对个数

从右向左

 1 #include<iostream>
 2 #include<cstring>
 3 using namespace std;
 4 int n, a[100000], s[100000], sum=0;
 5 
 6 int lowbit(int x){return x & -x;}
 7 int update(int x, int y){
 8     for(; x<=n; x+=lowbit(x))
 9         s[x] += y;
10 }
11 int getsum(int x){
12     int ans=0;
13     for(; x; x-=lowbit(x))
14         ans += s[x];
15     return ans;
16 }
17 
18 int main(){
19     ios::sync_with_stdio(false);
20     memset(a, 0, sizeof(a));
21     memset(s, 0, sizeof(s));
22     cin >> n;
23     for(int i=1; i<=n; i++) cin >> a[i];
24     
25     for(int i=n; i>=1; i--){
26         sum += getsum(a[i]);
27         update(a[i], 1);
28     }
29     cout << sum << "
";
30     return 0;
31 }

从左向右

 1 #include<iostream>
 2 #include<cstring>
 3 using namespace std;
 4 int n, a[100000], s[100000], sum=0;
 5 int lowbit(int x){return x & -x;} 
 6 int getsum(int x){
 7     int ans=0;
 8     for(; x<=n; x+=lowbit(x))
 9         ans += s[x];
10     return ans;
11 }
12 int update(int x, int y){
13     for(;x;x-=lowbit(x))
14         s[x]+=y;
15 }
16 
17 int main(){
18     ios::sync_with_stdio(false);
19     memset(a,0,sizeof(a));
20     memset(s,0,sizeof(s));
21     
22     cin >> n;
23     for(int i=1; i<=n; i++){
24         cin >> a[i];
25         sum+=getsum(a[i]);
26         update(a[i],1);
27     } 
28     cout << sum << "
";
29     
30     return 0;
31 }
原文地址:https://www.cnblogs.com/hnoi/p/10922429.html