這個借助例題來講解
題目求氣泡排序交換了多少次,分析一下,不難看出就是求逆序對的個數,首先明白逆序對的概念給定i,j滿足i < j && a[ i ]>a[ j ]則a[ i ]和a[ j ]就是一對逆序對。
求逆序對的做法,舉個例子:
給定序列
9 6 4 8 7
遍歷這個陣列,每次遇到乙個數,就把該數所在的樹狀陣列的位置處的數加一:
1 2 3 4 5 6 7 8 9
0 0 0 0 0 0 0 0 0
初始陣列值為0,代表插入0個數,sum(n)代表小於等於該數的個數,那麼大於該數的個數就是i-sum(n)
1 2 3 4 5 6 7 8 9
0 0 0 0 0 0 0 0 1
此時插入了乙個數,sum(9)=1,1-1=0
1 2 3 4 5 6 7 8 9
0 0 0 0 0 1 0 0 1
sum(6)=1 2-1=1
1 2 3 4 5 6 7 8 9
0 0 0 1 0 1 0 0 1
sum(4)=1 3-1=2
1 2 3 4 5 6 7 8 9
0 0 0 1 0 1 0 1 1
sum(8)=3 4-3=1
1 2 3 4 5 6 7 8 9
0 0 0 1 0 1 1 1 1
sum(7)=3 5-3=2
上面所有的得數相加就得到了最後結果:
0+1+2+1+2=6
這就是思路,思路清楚了就可以做題了,可是這道題資料很大,明顯開不了這麼大得樹狀陣列,乙個簡單得離散化就行了,先對樹狀陣列按照值的大小進行排序,新開乙個從序號1開始的連續的陣列,一一對映到樹狀陣列,最後對序號求逆序對就行了。
建立乙個結構體包含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
之後再利用樹狀陣列的特性就可以解決問題了
#include#include#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 前面的 有乙個...