KDTree學習筆記
不打算講定義這類的東西
對這玩意兒的理解大概就是一個玄學暴力叭...
如果題目有多維限制而且又很懶不想寫什麼CDQ啊樹套樹啊的話就可以無腦上KDTree
然後KDTree可以乾的事比較雜,大概可以分成下面幾類:
- 求K維空間最近鄰點 這大概就是KDTree最開始發明出來要乾的事情吧 可以求曼哈頓距離,歐幾里得距離的最近/遠點。具體需要通過一個類似於A*中的估價函式去實現。假如說當前搜到的最近距離是 \(ans\) ,在KDTree上的 \(x\) 點。那我們需要對點 \(x\) 的左右子樹進行一個估價來決定是否進入。假設要求曼哈頓距離最近點,對左子樹 \(ls\) 進行估價。我們在每個節點額外維護四個值,表示該點及其子樹中 x/y 座標的最大/小值(實際上就是每個點維護一個矩形區域)。然後我們就可以進行估價了。為了不影響正確性,估價的原則是 估算答案 >= 真實答案,所以不妨將估算答案當作查詢點到左子樹維護的矩形區域的四個角的曼哈頓距離的最大值。估價後優先進入價值大的子樹(因為可能會更優)。
- 對K維空間某個區域求和 嗯這個操作很像線段樹 就是進入一個節點之後判斷 如果該節點維護的矩形區域被詢問區域完全包含 那就用自身維護好的資訊更新答案 如果完全不相交 那就直接return 否則遞迴進兩個子樹進行查詢 很暴力很暴力的思想 注意如果再帶修改或者插入的話,那就需要定期重構。重構的方法有兩個,一個是插入節點數到達一定閾值之後重構,另一個是仿照替罪羊樹那樣,如果某個節點的左右子樹不平衡,那就拍扁重構一發。
常見估價:
還是看例題吧
Luogu4169 SJY擺棋子
求二維平面上到一個點的最近點 板子題
Luogu4148 簡單題
題意
支援兩個操作:單點加,矩形求和 強制線上 空間限制20M
Sol
強制線上所以沒法CDQ 20M所以沒法樹套樹
只能KDTree了嗚嗚嗚
Luogu4475 巧克力王國
啊也是板子題不講了不講了
Luogu2093 JZPFAR
題意
給定平面上 \(n\) 個點, \(m\) 次詢問,每次詢問平面上離詢問點 \((x,y)\) 第 \(k\) 遠的點的編號。 \(n\leq 10^5,k\leq 20\) 。
Sol
這題還行。
就是在全域性維護一個大小為 \(k\) 的小根堆。最開始裡面全是 \(0\) 。
在KDTree上找到了一個點,如果該點離詢問點的距離 > 堆頂離詢問點的距離,那就更新堆。
用最遠歐幾里得距離對子樹估價,如果有可能更新堆頂那就遞迴進去。
Luogu4357 K遠點對
題意
給定平面上 \(n\) 個點,詢問歐幾里得距離第 \(k\) 遠的點對間的距離。
Sol
仿照上題,還是維護一個小根堆
對於每個點去KDTree上找嘗試更新答案(就類似於上題的詢問
最開始要放 \(2k\) 個 $0 $ 進去,原因是每個點對會被重複統計兩遍。最後堆頂就是答案。
BZOJ4154 Generating Synergy
題意
給定一棵以 \(1\) 為根的有根樹,初始所有節點顏色為 \(1\) ,操作為 將 \(a\) 子樹中距離 \(a\) 不超過 \(l\) 的節點顏色染為 \(c\) ,或者詢問 \(a\) 的顏色。
Sol
觀察到每次就是把 \(dfn\in[dfn[a],dfn[a]+sze[a]-1]\land dep\in[dep[a],dep[a]+l]\) 的那些節點染色。把 \(dfn\) 作為第一維, \(dep\) 作為第二維放到二維平面上,這就變成了矩形染色,單點查詢的題,KDTree即可。
BZOJ3489 A simple rmq problem
題意
給定長為 \(n\) 的序列和 \(m\) 個詢問:在 \([l,r]\) 中找到在區間中只出現一次的數,如果有多個就找價值最大的那個。強制線上。
Sol
設 \(pre[i],suf[i]\) 分別表示 \(i\) 前面(或後面)第一個和 \(i\) 權值相同的位置 。那麼詢問就是查詢 \(pre[i]\in(1,l-1]\land i\in[l,r]\land suf[i]\in[r,n]\) 中最大的 \(val[i]\) 。放進三維KDTree中就是裸題了,每次查詢一個三維區間即可。
BZOJ3616 War
題意
一共有 \(k\) 個陣營,給定二維平面上的 \(n\) 個炮塔和每個炮塔的攻擊範圍。一共要進行 \(m\) 輪攻擊,每次會隨機一個炮塔並攻擊所有它能攻擊到的除了自己陣營的目標。一個炮塔被攻擊並不影響它攻擊其它炮塔。問進行 \(m\) 輪之後期望剩下多少個陣營,使得這些陣營所屬炮塔全部沒有被攻擊過。
Sol
首先可以求出對於第 \(i\) 個陣營有多少炮塔能攻擊到屬於它的炮塔,假設有 \(cnt\) 個,那麼該聯盟的貢獻就是 \(1\cdot (\frac{n-cnt}n)^m\) 。然後問題就變成了對於一個炮塔怎麼求多少炮塔會攻擊到它。這個東西不是很好求,但是我們每次可以用一個炮塔進行攻擊啊,這樣不就變成了在KDTree上打標記嘛。再拿bitset隨便記一下就好了。