洛谷P1168 中位數 Treap解法

2021-10-02 12:32:42 字數 1746 閱讀 2882

給出長度n(n<=100000) 的非負整數序列ai,求出前1,3,5…個數的中位數

正規的做法有用stl的優先佇列,維護乙個大根堆和乙個小根堆,構造乙個元素數量平衡的t1-r-t2結構。其中b是中位數,a1的所有值都小於r,並且用大根堆的性質表示出其內最大的元素,以方便在插入新的值時決定要如何插入。a2是值都大於等於r的小根堆,理由同上

但是,本著殺雞用牛刀的原則(抄板子),這個題還可以用名次樹來完成,n次插入,大約n/2次查詢名次,仍然是o(n

logn

)o(nlogn)

o(nlog

n)的級別,在1e5的情況下可行!

中位數即查詢排名n/2+1位次的數(n=1,3,5…)

用了p3369的板子

read()函式可以讀入乙個數字

insert(a,root)是插入數a

erase(a,root)刪除數a,有多個只刪除乙個

rank(a,root)返回a的名次

find(a,root)返回名次a的數

最後兩者結合可以找到後繼/前驅

本題只用到了insert和find

#include

"cstdlib"

#include

"iostream"

#include

"cstdio"

#include

"cstring"

#include

//佇列

#define update( cur ) if(cur-> left-> size)cur-> size = cur -> left->size + cur -> right -> size , cur -> value = cur -> right -> value

#define new_node( s , v , a , b ) ( & ( * st [ cnt++ ] = node ( s , v , a , b) ) )

#define merge( a , b ) new_node( a -> size + b -> size , b -> value , a , b )

#define ratio 4

int n, cnt, s, a;

inline

intread()

while

(isdigit

(ch)

) x = x *

10+ ch -

'0', ch =

getchar()

;return x * v;

}class

node

node()

};node* root,

* st[

300010

], t[

300010],

* null,

* father;

inline

void

maintain

(register node* cur)

intfind

(int x, node* cur)

intrank

(int x, node* cur)

void

insert

(int x, node* cur)

void

erase

(int x, node* cur)

//main之前都是板子內容

intmain()

return0;

}

洛谷 P1168 中位數

題目描述 給出乙個長度為n的非負整數序列a i 對於所有1 k n 1 2,輸出a 1 a 2 a 2k 1 的中位數。color red 即 color 前1,3,5,個數的中位數。輸入輸出格式 輸入格式 輸入檔案median.in的第1行為乙個正整數n,表示了序列長度。第2行包含n個非負整數a ...

洛谷 P1168 中位數

這個題很簡單 但是我要講3種做法 我們維護乙個小根堆乙個大根堆,其中大根堆的堆頂小於小根堆的所有元素,待加入元素大於大根堆堆頂元素就加入小根堆,反之加入大根堆,然後維護兩個堆元素數量,使得兩個堆的元素數量差為1,這樣我們取兩個堆中元素多的那個的堆頂就是答案 初始化的時候先往大根堆裡加入乙個元素,避免...

洛谷 P1168 中位數

給出乙個長度為n的非負整數序列a i 對於所有1 k n 1 2,輸出a 1 a 3 a 2k 1 的中位數。color red 即 color 前1,3,5,個數的中位數。輸入格式 輸入檔案median.in的第1行為乙個正整數n,表示了序列長度。第2行包含n個非負整數a i a i 10 9 輸...