貓貓tom和小老鼠jerry最近又較量上了,但是畢竟都是成年人,他們已經不喜歡再玩那種你追我趕的遊戲,現在他們喜歡玩統計。最近,tom老貓查閱到乙個人類稱之為「逆序對」的東西,這東西是這樣定義的:對於給定的一段正整數序列,逆序對就是序列中ai>aj且i第一行,乙個數n,表示序列中有n個數。
第二行n個數,表示給定的序列。序列中每個數字不超過10910^9109
給定序列中逆序對的數目。
輸入 #1
65 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 usingnamespace
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,...