洛谷P1908 逆序對(線段樹解法)

2022-05-27 08:57:14 字數 1624 閱讀 6185

貓貓tom和小老鼠jerry最近又較量上了,但是畢竟都是成年人,他們已經不喜歡再玩那種你追我趕的遊戲,現在他們喜歡玩統計。最近,tom老貓查閱到乙個人類稱之為「逆序對」的東西,這東西是這樣定義的:對於給定的一段正整數序列,逆序對就是序列中ai>aj且i第一行,乙個數n,表示序列中有n個數。

第二行n個數,表示給定的序列。序列中每個數字不超過10910^9109

給定序列中逆序對的數目。

輸入 #1

6

5 4 2 6 3 1

輸出 #1

11

思路:和poj2352類似,這個題可以先建一棵空樹,然後不斷查詢不斷插點。對於逆序對的定義已經很清楚了,在這裡應用桶排序的思想,每個葉子節點儲存的是這個數的個數。不考慮題目所給的輸入值1e9範圍的話,當從輸入讀到乙個數a[i]時,若求他的逆序數,只需要統計葉子節點i+1位置到最終位置的區間和(因為是按照輸入順序插入的,讀到第i個時前面i-1個數已經進入桶了,統計大於a[i]的數的個數更新ans即可。因為先建的是空樹,所以可以直接統計到最大範圍)。區間查詢完畢後進行當前點的插入,最終輸出ans。

這是數字元素範圍比較小的情況,但題目給的範圍是1e9,n的範圍是1e5,自然想到要進行離散化。逆序數隻涉及相對大小關係,就可以進行對映。比方說5,99999,853,6666666,119就可以對映成1,4,3,5,2且其相對大小關係並沒有改變,這樣就可以用陣列儲存了。

#include using

namespace

std;

int a[500005

];int bin[500005

];int cnt=0

;int

n;struct

segmenttree

t[500005*4];//

四倍n大小儲存所有節點

void build(int p,int l,int r)//

建樹 int query(int p,int l,int r,int l,int r)//

區間查詢 p是當前節點在t陣列的下標,l是當前節點覆蓋範圍左端點,r是當前節點覆蓋範圍右端點,l是題目中待查詢區間的左端點,r是待查詢區間右端點

void update(int p,int l,int r,int x)//

單點修改 p是當前節點在t陣列的下標,l是當前節點覆蓋範圍左端點,r是當前節點覆蓋範圍右端點,x是待插入的值

int mid=(l+r)/2

;

if(x<=mid)

else

t[p].dat=t[2*p].dat+t[2*p+1].dat;//

不要忘記遞迴完後要更新父節點

}int

main()

sort(bin+1,bin+n+1);//

排序(二分查詢的必要條件)

cnt=unique(bin+1,bin+cnt+1)-bin-1;//

unique函式實現去重,得到的cnt是去重後的bin陣列大小

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

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

cout

}

P1908 逆序對 線段樹題解

讀完題目,你的第一想法肯定是直接暴力就能過了。實際上在看完資料之後。qaq。好吧,肯定不能暴力,那 麼現在就要去尋找它的特徵。根據它的特徵,我們可以分析出要用線段樹去做這道題。那麼當我們確定這個演算法時,我 來的順序再排回來,然後根據每乙個數的大小對號入座,在入座的過程中我們計算在這個葉子節點的右邊...

洛谷 P1908 逆序對(線段樹區間求和 離散化)

逆序對就是序列中 ai aj且i用乙個flag陣列標記哪些數字已經放入陣列中,用線段樹求flag的字首和,求放入的數字前已經放入了多少個比他小的數字。include using namespace std define int long long define ios ios sync with s...

線段樹動態開點 洛谷P1908逆序對

題目鏈結 題目描述 貓貓tom和小老鼠jerry最近又較量上了,但是畢竟都是成年人,他們已經不喜歡再玩那種你追我趕的遊戲,現在他們喜歡玩統計。最近,tom老貓查閱到乙個人類稱之為 逆序對 的東西,這東西是這樣定義的 對於給定的一段正整數序列,逆序對就是序列中ai aj且i輸入格式 第一行,乙個數n,...