最近進入了賽後養生模式,感覺身體被掏空,還要補課···學點養生資料結構。
正交區域的精確定義我不知道…而一般來說,乙個空間內查詢乙個特定長方體裡面的資訊,乙個平面內查詢某個長方形的查詢都可以稱作正交區域查詢。而二維平面的不規則的區域查詢我們可以轉化為多個正交區域查詢的並。
而許多資訊的查詢是可以轉化為正交區域查詢的,例如問一堆員工中,年齡在[a,b],工資在[l,r]中的有幾個。這個有很多做法,什麼樹套樹之類的。而一種思路是,把員工的年齡x和工資y對映到二維平面上的點(x,y)上,這樣就可以進行正交區域查詢了,即查詢乙個矩形中點的個數。
我們需要乙個資料結構,乙個可以在任何維數下使用的資料結構。(樹套樹只適用二維,他和一維的樹**差別還是挺大的)
先解釋一下名字,k是維數,d是dimension,即維。「樹」表明他是樹的結構。
基本地,kd樹中乙個節點儲存了:
const
int k=2;
struct kd_tree
tr[n];
如上**,d為節點儲存的原圖的點座標,son為兒子,第二行儲存了k維空間域。
構造大體思想:
kd樹是一顆平衡二叉樹,其中每個非葉節點,可以想象乙個超平面,用來分割其儲存的空間域,其中超平面垂直於座標軸。
主線:
垂直某個軸,意味著以這個軸的座標為關鍵字來操作。
例如這次要垂直x軸,我們取當前點集的x座標的中位數,然後把它作為切分點,切分點作為父節點,即kd樹中新節點儲存的點;切開的兩邊的點分別屬於左右子樹的點集。
這是乙個例子
下面給出構造**
#include
#include
#include
#include
using namespace std;
#define fo(i,j,k) for(i=j;i<=k;i++)
#define fd(i,j,k) for(i=j;i>=k;i--)
#define cmax(a,b) (a#define cmin(a,b) (a>b?a=b:a)
struct p
a[n];
struct kd_tree
tr[n];
int d,root;
int i,n;
bool operator
int build(int l,int r,int d)
int main()
nth_element 就是找出第n大的元素,把它放到第n位,同時它左邊的元素都比它大,右邊的都比它小。其實就是快速選擇。
用這個構造以後,我們就可以很方便的正交區域查詢了,二維時,時間複雜度為o(
n∗sq
rt(n
)),與樹套樹同階。分析詳見清華大學出版社的《計算幾何——演算法與應用》。
估價這是用於優化查詢複雜度的東西。
這裡估價估的是目標點到當前查詢區域距離的上界和下界。
設a為查詢點,l,r表示域的某個座標的min和max。
那麼曼哈頓距離最小
max(0,lx-ax)+
max(0,ax-rx)+
max(0,ly-ay)+
max(0,ay-ry);
每個座標分三種情況討論,發現是這樣的。
而曼哈頓距離最大很類似。
max(abs(lx-ax),abs(rx
-ax))+
max(abs(ly-ay),abs(ry-ay));
接下來還有歐幾里得距離,我們不開方,也分三種情況討論。很類似就不寫了。
切比雪夫距離?轉45°就成了曼哈頓。
修改查詢
查詢與(x,y)最近的點的思路是這樣的:
我們從根kd-tree,對每個節點x,我們先用它更新答案,然後再對兩個兒子做一次估價,估價值優的優先訪問。當然,如果估價值比答案要劣,那就不用走了,因為估價函式是最優的情況了,最優都更劣,那就不用管了。
隨機資料下,這樣找一次是o(log n)的,而構造可以卡成o(sqrt(n))。
構造之後講。
題目**裡有一些新學的,比較優美的,優化**排版的方法。
1,【sdoi2010】hide and seek
#include
#include
#include
#include
using namespace std;
#define fo(i,j,k) for(i=j;i<=k;i++)
#define fd(i,j,k) for(i=j;i>=k;i--)
#define cmax(a,b) (a#define cmin(a,b) (a>b?a=b:a)
typedef long long ll;
typedef double db;
const int n=100005,k=2;
struct p
a[n];
struct kd_tree
tr[n];
int d,root;
int ans,tp[2],ax,ay,lx,ly,rx,ry,p;
int i,n;
bool operator
int build(int l,int r,int d)
int calc(int tar,int
x,int sig)
void get(int tar,int
x,int d,int sig)
int f1=calc(tar,tr[x].son[0],sig),t1=tr[x].son[0];
int f2=calc(tar,tr[x].son[1],sig),t2=tr[x].son[1];
if (f1*sig>f2*sig||!t1) swap(f1,f2),swap(t1,t2);
if (t1&&f1*sig
*sig)
get(tar,t1,d,sig);
if (t2&&f2*sig
*sig)
get(tar,t2,d,sig);
}int main()
printf("%d\n",ans);
}
參考
crazy的計算幾何ppt
n+e的教學pdf《k-d tree在資訊學競賽中的應用》
清華大學出版社《計算幾何——演算法與應用》
KD tree學習筆記
如上圖 a 我們先對待識別的物體的影象進行sift特徵點的檢測和特徵點的描述,然後得到了sift特徵點集合。接下來生成物體目標描述要做的就是對特徵點集合進行資料組織,形成一種特殊的表示,其作用是為了加速特徵點匹配的過程。所謂的特徵點匹配本質上是乙個通過距離函式 例如歐式距離 在高維向量之間進行相似性...
學習筆記 kd tree
kd tree用來維護n維空間中的點的一種資料結構。支援插入 刪除 查詢k臨近 包括最遠點對和最近點對 kd tree本質是一顆二叉樹。每一層選擇乙個維度,找到當前維度的中點 讓樹盡量平衡 經過這個點,在當前維度切割,分成左右兩個子樹。通常維度的選擇是順次迴圈的,較易實現。更優的方法是找到方差最大的...
KD Tree學習筆記
kdtree是一種用於分割k維資料空間的資料結構,主要應用於多維空間關鍵資料的搜尋。例如 範圍搜尋和最近鄰搜尋 kdtree的每個節點表示k維空間的乙個點 每次空間劃分按照輪轉法劃分,即如果這次選擇了在第i維上劃分,則下一次就在 i 1 k上劃分 int id,n,k,c struct p p ma...