1. 程式人生 > >【learning】kd-tree

【learning】kd-tree

應該 原因 處理 math 二叉 。。 答案 dal 添加

吐槽
kd-tree這個東西很早就聽說過了但是qwq一直沒有去了解

(原因的話。。啊哈哈聽說是什麽跟二維平面之類的東西有關的所以就慫掉了qwq沒錯就是慫qwq)

但其實好像。。真的很暴力啊qwq知道思路之後隨便亂搞系列qwq

時間復雜度什麽的應該是玄學恩qwq(網上看到有dalao說期望復雜度是O(n^(d-1)/d),不會證就是這樣qwq)

正題

首先kd-tree是一棵類似二叉查找樹的東西

拿二維的kd-tree為例,每個數據有兩個關鍵值\(x\)\(y\)

那麽kd-tree的總的思路就是,每層根據一個關鍵值(記為\(val\)好了)來排序,這兩個關鍵值輪著來(其實就是。。第一層按照\(x\)

排序,第二層\(y\),然後第三層又是\(x\),以此類推)

kd-tree滿足的性質是,\(x\)左子樹中所有節點的\(val\)小於\(x\)\(val\),右子樹中所有節點的\(val\)大於\(x\)\(val\)

比如說我們現在要構建\(n\)組數據的kd-tree,那麽方法很簡單

首先stl有一個十分吼的東西叫做nth_element(),具體用法是將\([l,r]\)這個區間內的第\(k\)個數放到這段區間中的第\(k\)個位置,然後前面的數小於它,後面的數大於它,但是不保證有序

調用:nth_element(a+l,a+mid,a+r+1,cmp)

如果說沒有修改操作(bzoj2850),那麽就是遞歸處理,build(),每次把區間的中間那個數拎出來,用nth_element處理一下,然後左邊的就是mid的左子樹,右邊的就是右子樹,然後遞歸處理

(所以說就是怎麽亂搞都ok啦ovo)

那麽這個東西有啥用呢?其實就是相當於排了個序,我們對於每個節點多維護4個值,分別是\(i\)子樹下\(x\)的最大最小值和\(y\)的最大最小值,然後再維護其他的東西(什麽sum啊之類的具體題目具體分析)

這樣如果說我要查某個範圍,我就能快速判斷出這個子樹是否需要遍歷,如果說沒有交集直接跳過,如果完全包含那直接把整個子樹的信息拿來更新答案之類的,如果部分包含那就沒辦法了老老實實遍歷咯

寫起來還是十分簡潔的ovo

如果說有修改操作(bzoj4066),那麽就不能預處理出整棵kd-tree了,要一個一個點insert之類的

insert的話其實也很簡單,就是按照前面說的排序方式每次判斷小於的話就往左子樹走反之右子樹,找到應該在的位置把信息存進去就好了

但是這就涉及到一個問題,這樣添加的話是可能退化成一條鏈的。。那就很gg了

所以我們需要不定時重構(有沒有想到替罪羊啊哈哈哈。。好吧其實重構的方式確實有點像恩qwq)

其實就是把當前得到的所有值跑一遍無修改操作的build函數就好了

這樣就可以保證變成一條鏈的樣子不會持續太久。。那麽復雜度就會優秀很多了(然而還是玄學qwq)

可以用來處理一些強制在線的區間修改查詢,甚至可以用來處理一些cdq分治的題目(hdu5126)

大概就是這樣咯ovo

【learning】kd-tree