樹狀陣列求逆序數

2021-06-20 06:16:14 字數 1811 閱讀 8542

逆序數就是數中各位在它前面有多少個數比它大,求出這些元素個數之和。

今天看了個樹狀陣列,可以很好的解決這個問題,普通方法需要o(n^2)複雜度,用樹狀陣列只需要o(nlongn)

樹狀陣列實際上還是乙個陣列,只不過它的每個元素儲存了跟原來陣列的一些元素相關的結合值。

若a為原陣列,定義陣列c為樹狀陣列。c陣列中元素c[ i ]表示a[ i –lowbit( i ) + 1]至a[ i ]的結合值。

lowbit(i)是i的二進位制中最後乙個不為零的位數的2次方,可以這樣計算

lowbit(i)=x&(-x)

lowbit(i)=x&(x^(x-1))

當想要查詢乙個sum(n)時,可以依據如下演算法即可:

step1: 令sum = 0,轉第二步;

step2: 假如n <= 0,演算法結束,返回sum值,否則sum = sum + cn,轉第三步;

step3:  令n = n – lowbit(n),轉第二步。

n = n – lowbit(n)這一步實際上等價於將n的二進位制的最後乙個1減去。而n的二進位制裡最多有log(n)個1,所以查詢效率是log(n)的。

修改乙個節點,必須修改其所有祖先,最壞情況下為修改第乙個元素,最多有log(n)的祖先。所以修改演算法如下(給某個結點i加上x):

step1: 當i > n時,演算法結束,否則轉第二步;

step2: ci = ci + x, i = i + lowbit(i)轉第一步。

i = i +lowbit(i)這個過程實際上也只是乙個把末尾1補為0的過程。

求逆序的思路:

可以把數乙個個插入到樹狀陣列中, 每插入乙個數, 統計比他小的數的個數,對應的逆序為 i- getsum( data[i] ),其中 i 為當前已經插入的數的個數, getsum( data[i] )為比 data[i] 小的數的個數,i- getsum( data[i] ) 即比 data[i] 大的個數, 即逆序的個數。最後需要把所有逆序數求和,就是在插入的過程中邊插入邊求和。

下面是**:

[cpp]view plain

copy

#include 

using

namespace std;  

#define  n  10

struct node;  

node d[n+1];  

int inverse[n+1];   

int count[n];   

int cmp(

const

void*a,const

void*b)  

int lowbit(

int t)  

void modify(

int pos,int num)  

}  int sum(

int end)  

return sum;  

}  int main()  

qsort(d+1,n,sizeof(node),cmp);  

int id=1;  

count[d[1].pos]=1;  

for(

int i=2;i<=n;i++)  

int num=0;  

for(

int i=1;i<=n;i++)  

cout<

return 0;  

}  

中間用到了排序,需要統計位於下標i處比i小的數,然後在樹狀陣列中計算每個位置的和。

排序複雜度o(nlogn), 計算逆序數和的時候也是o(nlogn).

這裡處理的是乙個數的不同位,當然可以擴充套件到很多數。

樹狀陣列求逆序數

chikachika說希望和我一起做學園偶像的時候,我真的很開心。watanabeyouwatanabeyou 曜是千歌的青梅竹馬,但是aqoursaqours成立以後,千歌似乎總是與梨子在一起,而把曜冷落了。為了讓千歌知曉自己的心意,曜醬決定做一件大事!她決定把乙個給定的11 nn的排列 1 ai...

樹狀陣列 求逆序數

一.樹狀陣列介紹 1 性質 樹狀陣列本質上就是乙個陣列,它與普通陣列不同之處在於它的某些元素維護的是一段區間的資訊,已區間和為例,若i為奇數,則第i個元素就是源資料的第i個元素,若i為偶數,則第i個元素維護的是 i 2 k 1,i 這段區間的和,k代表i的二進位制末尾0的個數。2 作用 樹狀陣列常用...

樹狀陣列求逆序數

1 什麼是逆序數?在乙個排列中,如果一對數的前後位置與大小順序相反,即前面的數大於後面的數,那麼它們就稱為乙個逆序。乙個排列中逆序數的總數就是這個排列的逆序數。2 用樹狀陣列求逆序數的總數 2.1該背景下樹狀陣列的含義 我們假設乙個陣列a n 當a n 0時表示數字n在序列中沒有出現過,a n 1表...