---
# System prepended metadata

title: 逆序數對

---

# 逆序數對

#### 定義: 
設一數列s[10]與其中兩index:i,j,當0<=i<j<=9 且s[i]>s[j]時,兩數被稱為逆序數對

#### 作法:
1. 掃一遍陣列 => 索引號i為嚴格遞增
2. 根據定義,只要找小於i的所有數中大於s[i]的個數就是當前的逆序數對個數
3. 掃完後把所有找到的逆序數對相加就是所有的逆序數對

#### 時間複雜度優化 :
在找前i個有幾個數比s[i]大時,可以利用BIT技巧計算
##### 比s[i]大的各數=BIT裡的數-BIT的query(比s[i]小的數)

```cpp=
int bit[MAXN];

void update(int n){
  while(n<=MAXN){
    bit[n]++;
    n+=n&-n;
  }
}

int query(int n){
  int sum=0;
  while(n>0){
    sum+=bit[n];
    n-=n&-n;
  }
  return sum;
}

int main(){
    ......
    int ans=0;
    for(int i=0;i<n;i++){
      ans+=i-query(s[i]);
      update(s[i]);
    }
}
```

#### 記憶體優化 :

離散化:
因為我們只要比大小,所以可以利用離散化把索引值壓縮到BIT的大小

```cpp=
sort(descrete.begin(),descrete.end());
for(int i=0;i<n;i++){
     arr[i]=lower_bound(descrete.begin(),descrete.end(),arr[i])-descrete.begin()+1;
    //+1是因為BIT的index要從1開始
}
```

#### 完整程式碼
```cpp=
#include <bits/stdc++.h>
#define MAXN 10005
using namespace std;

int bit[MAXN]={0};

void update(int n){  //單點修改
  while(n<=MAXN){
    bit[n]++;
    n+=n&-n;
  }
}

int query(int n){  //前綴和查詢
  int sum=0;
  while(n>0){
    sum+=bit[n];
    n-=n&-n;
  }
  return sum;
}

int main(){
  int n;
  cin >> n;
  vector<int> arr(n);  //紀錄數列
  vector<int> descrete;  //利散化用
  
  for(int i=0;i<n;i++){
    cin >> arr[i];
    descrete.push_back(arr[i]);
  }
  
 //離散化
  sort(descrete.begin(),descrete.end());
  for(int i=0;i<n;i++){
    arr[i]=lower_bound(descrete.begin(),descrete.end(),arr[i])-descrete.begin()+1;
  }

  //BIT維護&計算答案
  int ans=0;
  for(int i=0;i<n;i++){
    ans+=i-query(arr[i]);
    update(arr[i]);
  }
  
  cout << ans << '\n';
  return 0;
}
```