仔细想想,如果存在正整数 i, j 使得 1 ≤ i < j ≤ n 且 A[i] > A[j],则称为一个逆序对。 这就意味着如果想要统计逆序对,就要在数列中 从左向右依次算出 每个数右侧比自己小的数的个数,最后将将其相加。但是,当我们新读入一个数时,根本不清楚后面还未读进来的数是怎样的!
所以对于此类问题,有两种解决方案:
- 从右向左读取 统计已经读取的数中比自己小的个数。
- 从左向右读取 统计已经读取的数中比自己大的个数。
根据树状数组向上更新、向下查询的特性,我们更习惯用从右到左向上查询的方法。(其实从左到右向上查询也不是无法实现,只要求出顺序对个数 再用组合总数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 }