清华的论文和网上的博客已经非常详细了,在此就不赘述了
其实它比较像可持久化线段树,只不过每一层的顺序是不同的(就是维度交替有序)
然后build、insert操作就和可持久化线段树一样了
然后还有一个重构函数(替罪羊树的思想),就是直接把一个不平衡子树的所有节点存下来,然后build一下(其实非常好写的)
(之前一直都觉得很难写,其实写出来就只有2行)
写多了就熟练了,KD树还是比较板的
KD树的复杂度瓶颈在于查询,而查询的关键在于估价函数
一般KD树T了都是估价函数的问题
注意,一定要把0号点的边界赋初值!!!
例题:[Sdoi2010] Hide and Seek
小猪iPig在PKU刚上完了无聊的猪性代数课,天资聪慧的iPig被这门对他来说无比简单的课弄得非常寂寞,为了消除寂寞感,他决定和他的好朋友giPi(鸡皮)玩一个更加寂寞的游戏---捉迷藏。 但是,他们觉得,玩普通的捉迷藏没什么意思,还是不够寂寞,于是,他们决定玩寂寞无比的螃蟹版捉迷藏,顾名思义,就是说他们在玩游戏的时候只能沿水平或垂直方向走。一番寂寞的剪刀石头布后,他们决定iPig去捉giPi。由于他们都很熟悉PKU的地形了,所以giPi只会躲在PKU内n个隐秘地点,显然iPig也只会在那n个地点内找giPi。游戏一开始,他们选定一个地点,iPig保持不动,然后giPi用30秒的时间逃离现场(显然,giPi不会呆在原地)。然后iPig会随机地去找giPi,直到找到为止。由于iPig很懒,所以他到总是走最短的路径,而且,他选择起始点不是随便选的,他想找一个地点,使得该地点到最远的地点和最近的地点的距离差最小。iPig现在想知道这个距离差最小是多少。 由于iPig现在手上没有电脑,所以不能编程解决这个如此简单的问题,所以他马上打了个电话,要求你帮他解决这个问题。iPig告诉了你PKU的n个隐秘地点的坐标,请你编程求出iPig的问题。
Input
第一行输入一个整数N 第2~N+1行,每行两个整数X,Y,表示第i个地点的坐标
Output
一个整数,为距离差的最小值。
Sample Input
4
0 0
1 0
0 1
1 1
Sample Output
1
Hint
对于30%的数据,N<=1000 对于100%的数据,N<=500000,0<=X,Y<=10^8 保证数据没有重点保证N>=2
注意:他们选的地点是在给出来的地点中选,不是从任意一个点出发(害得我想了好久模拟退火)
然后这就是一个KD板子题了
存个模板:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
inline int gi()
{
char c;int num=0,flg=1;
while((c=getchar())<'0'||c>'9')if(c=='-')flg=-1;
while(c>='0'&&c<='9'){num=num*10+c-48;c=getchar();}
return num*flg;
}
#define N 500005
#define MD 2
#define lc ch[i][0]
#define rc ch[i][1]
int D,DF;
int ch[N][2],rt,tot;
int siz[N],tmp[N],cnt;
int a[N][MD],mi[N][MD],mx[N][MD];
void pushup(int i)
{
for(int j=0;j<DF;j++){
mi[i][j]=min(min(mi[lc][j],mi[rc][j]),a[i][j]);
mx[i][j]=max(max(mx[lc][j],mx[rc][j]),a[i][j]);
}
siz[i]=siz[lc]+siz[rc]+1;
}
bool cmp(int x,int y){return a[x][D]<a[y][D];}
void build(int &i,int l,int r,int d)
{
int mid=(l+r)>>1;D=d;
nth_element(tmp+l,tmp+mid,tmp+r+1,cmp);
i=tmp[mid];lc=rc=0;
if(l<mid)build(lc,l,mid-1,(d+1)%DF);
if(r>mid)build(rc,mid+1,r,(d+1)%DF);
pushup(i);
}
void dfs(int i)
{
if(!i) return;
dfs(lc);tmp[++cnt]=i;dfs(rc);
}
void insert(int &i,int d,int *x)
{
if(!i){
i=++tot;siz[i]=1;
for(int j=0;j<DF;j++)
a[i][j]=mi[i][j]=mx[i][j]=x[j];
return;
}
bool flg=(a[i][d]<=x[d]);
insert(ch[i][flg],(d+1)%DF,x);
pushup(i);
if(1.0*max(siz[lc],siz[rc])>0.75*siz[i]){
cnt=0;dfs(i);
build(i,1,cnt,d);
}
}
int dis(int *x,int *y)
{
int sum=0;
for(int j=0;j<DF;j++)
sum+=abs(x[j]-y[j]);
return sum;
}
int maxdis(int i,int *x)
{
int sum=0;
for(int j=0;j<DF;j++)
sum+=max(abs(mi[i][j]-x[j]),abs(mx[i][j]-x[j]));
return sum;
}
int mindis(int i,int *x)
{
int sum=0;
for(int j=0;j<DF;j++)
sum+=max(max(mi[i][j]-x[j],x[j]-mx[i][j]),0);
return sum;
}
int ans,pos;
void querymax(int i,int *x)
{
if(!i)return;
if(maxdis(i,x)<=ans)return;
ans=max(ans,dis(a[i],x));
if(lc&&rc&&maxdis(lc,x)<maxdis(rc,x))querymax(rc,x),querymax(lc,x);
else querymax(lc,x),querymax(rc,x);
}
void querymin(int i,int *x)
{
if(!i)return;
if(mindis(i,x)>=ans)return;
if(pos!=i)ans=min(ans,dis(a[i],x));
if(lc&&rc&&mindis(lc,x)>mindis(rc,x))querymin(rc,x),querymin(lc,x);
else querymin(lc,x),querymin(rc,x);
}
int val[MD];
int main()
{
DF=2;
mi[0][0]=mi[0][1]=1000000000;
mx[0][0]=mx[0][1]=0;
int n,i,tt,aans=1000000000;
n=gi();
for(i=1;i<=n;i++){
val[0]=gi();val[1]=gi();
insert(rt,0,val);
}
for(i=1;i<=n;i++){
ans=-1;querymax(rt,a[i]);tt=ans;
pos=i;
ans=1000000000;querymin(rt,a[i]);
aans=min(aans,tt-ans);
}
printf("%d",aans);
}