樹狀陣列 求逆序對 排序

2021-08-20 00:11:25 字數 1816 閱讀 5580

首先需要了解逆序對是什麼

逆序對就是如果i > j && a[i] < a[j],這兩個就算一對逆序對。其實也就是對於每個數而言,找找排在其前面有多少個比自己大的數。

那麼思路就來了,樹狀陣列又一次地優化了這種「需要遍歷」的情況。那不就很容易了嗎?依次把序列裡的數放到樹狀陣列中的a[i]上去(實際是以c[i]形式的插入函式),注意a[i]是以數值大小從小到大排列的。先插入的說明排在序列的前面,那麼後插入的就可以看看之前插入的比你大的數有多少,即i-sum(i),其實也就是看序列前面比你大的數有多少個,即找逆序對。

通過樹狀陣列找逆序對的原理(**,我看了就懂了):

了解技巧「離散化」

:這個技巧很有侷限性(至少以我目前的認知來說),幾乎只適合在樹狀陣列求逆序對來結合使用的。

什麼時候要用這個技巧呢?根據以上說的原理,我們知道需要以「數值大小」作為a[i]標準來公升序排,所以需要給c陣列開元素最大可能值的記憶體。

但萬一輸入的資料很大,那麼c陣列豈不是要開很大?記憶體超限!!

而如果要用離散化,只需要給c陣列開元素數量的記憶體。

建立乙個結構體包含val和id, val就是輸入的數,id表示輸入的順序。然後按照val從小到大排序,如果val相等,那麼就按照id排序。

如果沒有逆序的話,肯定id是跟i(表示拍好後的順序)一直一樣的,如果有逆序數,那麼有的i和id是不一樣的。所以,利用樹狀陣列的特性,我們可以簡單的算出逆序數的個數。

如果還是不明白的話舉個例子。(輸入4個數)

輸入:9 -1 18 5

輸出 3.

輸入之後對應的結構體就會變成這樣

val:9 -1 18 5

id:  1  2  3  4

排好序之後就變成了

val :  -1 5 9 18

id:      2 4  1  3

2 4 1 3 的逆序數 也是3

之後再利用樹狀陣列的特性就可以解決問題了

我覺得很神奇,直接得到「離散化」的結論:把原序列中每個元素的值和下標存到乙個結構體node裡去,之後把node陣列按元素值大小從小到大排序(注意結構體裡的過載《運算子的寫法 不是男左女右了我結論有誤t t 反正考場上試一試即可),這樣得到的結點的下標值即是離散化結果,等效於原序列的數值。把這些下標值當成原序列,按照樹狀陣列求逆序對的原理做。

習題:排序

大致思路

這個就是逆序對的定義呀!求逆序對的模板題。

這道題如果不離散化,c開1e9記憶體,超限,所以離散化,c只需要開5e5記憶體。

ac**

#include#includeusing namespace std;

const int maxn=500001;

int c[maxn];

struct node

return res;

}int main()

sort(node+1,node+1+n);

long long ans=0;

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

cout<

return 0;

}

樹狀陣列求逆序對

題目描述 給定乙個陣列a,它包含n個整數,分別是a 1 a 2 a n 如果存在下標i和j,使得 i j 且 a i a j 同時成立,則 i,j 就為乙個 逆序對 那麼a陣列總共有多少對不同的 逆序對 輸入格式 1247.in 第一行為n 1 n 100000 接下來是n行,每行乙個長整型範圍內的...

樹狀陣列求逆序對

很久以前就學了樹狀陣列,也知道可以用來求逆序對,然而一直沒弄明白他是怎麼實現的 可能當時沒搞清楚逆序對是什麼吧。逆序對就是如果i j a i a j 這兩個就算一對逆序對,簡單來說,所有逆序對的個數和就是找每乙個數的前面有幾個比他的大的數,他們加起來的和就是逆序對的總數。知道什麼是逆序對後就好辦了,...

樹狀陣列 求逆序對

樹狀陣列可以解決線段樹能夠解決的問題,且更加節省空間。線段樹的講解 可以看這位大佬的部落格 樹狀陣列的講解 另一位大佬的部落格 這裡主要寫一下利用樹狀陣列來求解逆序對的個數。簡單來說就是一段序列裡面每個數所在位置之前的位置上比這個數大的數字個數之和。例如 1 2 3 5 4 只有 4 前面的 有乙個...