感受最近一直在學東西來着。函數
至於緣由?學習
仍是我太弱了,每次看一道題:啥?這是什麼?根本沒學過啊。ui
索性這段時間就多學點新知識吧。spa
提及來,我如今最近根本不會取標題名字了,就隨意一點吧。翻譯
仍是這樣一個一個的\(part\)寫起來比較舒服。code
咱們先來理解一下\(K\)、\(D\)和\(Tree\)吧排序
首先\(Tree\)是什麼?你本身回答吧。遞歸
而後\(K\)是什麼?\(K\)固然就是\(K\)啊,仍是什麼?element
\(D\)?彷佛是\(demensional\)??也就是維度的意思博客
這樣就能解釋爲啥\(K\)就是\(K\)了
因此翻譯過來就是「K維樹」咯。
所以,\(KD-Tree\)用來分割\(K\)維空間,而後能夠在上面搞各類各樣的事情?
彷佛就是這樣的。
顯然的,在咱們的空間中,有一堆的點。
咱們如今要處理他們。
因此咱們選擇任意一個維度排序
而後選擇中間那個點的這一維來分割空間。
按照這一維排序後左右就分紅了兩部分。
這樣子就能夠分割空間了。(有一個\(STL\)的函數叫作\(nth\_element\),能夠了解一下)
(據說維度不能那麼隨意的選擇,好比你一直只按照一個維度劃分彷佛就不是很好?)
(網上的博客主要是推薦按照每一個維度依次分割,若是全部維度都分割完了就再從第一個開始循環)
(彷佛還有一種更好的方法?算下方差什麼的,反正我是不打算用這種啦)
咱們如今已經把空間給分割,對於每一塊分割出來的空間,裏面有若干個點。
咱們對於這些點維護一些信息,在回答詢問的時候,利用這些信息估算一下答案,
若是最有狀況下的答案不優於當前答案,咱們就不在這個空間內計算答案。
聽着頗有道理?
怎麼越聽越以爲像剪枝?
恩,好像就是剪枝誒!
因此咱們的\(KD-Tree\)也是一個暴力?
反正我是這麼認爲的。
首先咱們須要一個\(Build\)函數來構建\(KD-Tree\)
因而它大概長成這個樣子
int Build(int l,int r,int nD) { int x=(l+r)>>1;D=nD; nth_element(&a[l],&a[x],&a[r+1]); t[x].d[0]=t[x].mn[0]=t[x].mx[0]=a[x].d[0]; t[x].d[1]=t[x].mn[1]=t[x].mx[1]=a[x].d[1]; if(l<x)ls=Build(l,x-1,nD^1),update(x,ls); if(r>x)rs=Build(x+1,r,nD^1),update(x,rs); return x; }
對於插入操做,咱們模仿\(Build\)的這個遞歸操做,
對於當前節點所掌控的空間進行當前維度的比較,檢查應該分像左側仍是右側。
等等?這聽起來怎麼這麼像\(SBT\)??反正我也是這麼以爲的
也許\(KD-Tree\)就是\(SBT\)在空間上的拓展???
話說回來,\(KD-Tree\)在處理實際問題的時候,不一樣的剪枝函數要本身仔細思考,這樣纔可以更快。
據說有的時候由於插點插得太多了,致使\(KD-Tree\)變得很是的不平衡,
咱們能夠相似替罪羊樹同樣把它推倒重建。
對於每一個節點咱們額外維護一個\(size\)
每次\(check\)一下當前節點左右子樹的\(size\)的比值時候超過了設定的\(alpha\)
若是超過了直接拍扁重建一次就好啦
qaq,蜜汁不難???