来省队集训被吊打,于是无聊学了一下kd-tree,挺好玩的东西。
kd-tree是一种支持查询平面最近点(其实是k维,但这种题目比较少)的数据结构,单次理论时间复杂度O(√n),但实际是非常快的,可以说kd-tree就是一种比较优化的暴力。
kd-tree的思想是将平面进行分割,第一次按第一维分割,第二次按第二维分割,然后接着按第一维分割,直至每个叶子节点只包含一个点,类似线段树的结构。查询时,先查询到叶子节点,然后通过回溯,对于每一个节点算出,最小的可能距离,如果小于当前的ans,就向下查询。同样,kd-tree也可以建成平衡树的模式,这样的优势是可以插入节点。
模板:
bzoj1941 http://www.lydsy.com/JudgeOnline/problem.php?id=1941
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#define maxn 500010
#define inf 1000000000
using namespace std;
int n,m,cur,ans,root;
int x[maxn],y[maxn];
struct P
{
int mn[2],mx[2],d[2],lch,rch;
int& operator[](int x) {return d[x];}
friend bool operator<(P x,P y) {return x[cur]<y[cur];}
friend int dis(P x,P y) {return abs(x[0]-y[0])+abs(x[1]-y[1]);}
}p[maxn];
struct kdtree
{
P t[maxn],T;
int ans;
void update(int k)
{
int l=t[k].lch,r=t[k].rch;
for (int i=0;i<2;i++)
{
t[k].mn[i]=t[k].mx[i]=t[k][i];
if (l) t[k].mn[i]=min(t[k].mn[i],t[l].mn[i]);
if (r) t[k].mn[i]=min(t[k].mn[i],t[r].mn[i]);
if (l) t[k].mx[i]=max(t[k].mx[i],t[l].mx[i]);
if (r) t[k].mx[i]=max(t[k].mx[i],t[r].mx[i]);
}
}
int build(int l,int r,int now)
{
cur=now;
int mid=(l+r)/2;
nth_element(p+l,p+mid,p+r+1);
t[mid]=p[mid];
for (int i=0;i<2;i++) t[mid].mx[i]=t[mid].mn[i]=t[mid][i];
if (l<mid) t[mid].lch=build(l,mid-