【学习笔记】KD-Tree
前言
早有耳闻,只是一直懒得学,搞完军训没事做,就顺便来学一学。
正题
维护信息
废话。
建树
单独考虑某一个点上的划分方法时,假设我们已经选择完了根据哪个维度进行划分,那么为了保持整个树尽量优秀,我们希望左右子树尽量平均,因此应该选择在该维度下的 中位数 所代表的点,将区间内的点进行划分。
可以使用 nth_element
函数进行操作,具体来说他可以将第
需要注意与线段树将点存在叶子节点上不同,
如何选择该节点根据哪个维度进行划分?可以选择 方差最大 的维度 并不懂原理。
则构建复杂度为
插入
当
删除
需要支持动态删除时,可以使用惰性删除的方法,也就是在该点上打一个
重构
不难发现,在上面插入与删除的操作中,
考虑类似替罪羊树的方法,定义一个重构常数
剪枝
由于
习题
[CQOI2016]K远点对
已知平面内
个点,求欧氏距离第 远的点对的距离。
首先考虑
考虑在某一节点上,当前最优解为
那拓展到第
需要注意的是,该点对是无序的,因此
//Code By CXY07
#include<bits/stdc++.h>
using namespace std;
//#define FILE
#define int long long
//#define LL long long
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define fst first
#define scd second
#define inv(x) ksm(x,mod - 2)
#define lowbit(x) (x & (-x))
#define p2(x) ((x) * (x))
const int MAXN = 1e5 + 10;
const int INF = 2e9;
const double PI = acos(-1);
//const int mod = 1e9 + 7;
//const int mod = 998244353;
//const int G = 3;
struct NODE {
int x,y;
} s[MAXN];
template<typename T> inline void read(T &a) {
a = 0; char c = getchar(); int f = 1;
while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
while(c >= '0' && c <= '9') {a = a * 10 + (c ^ 48); c = getchar();}
a *= f;
}
int n,k,root;
int ls[MAXN],rs[MAXN];
int xmax[MAXN],xmin[MAXN],ymax[MAXN],ymin[MAXN];
priority_queue<int,vector<int>,greater<int> > Q;
bool cmpx(NODE &a,NODE &b) {return a.x < b.x;}
bool cmpy(NODE &a,NODE &b) {return a.y < b.y;}
void pushup(int x) {
xmax[x] = xmin[x] = s[x].x;
ymax[x] = ymin[x] = s[x].y;//首先设为只有自己
if(ls[x]) {
xmax[x] = max(xmax[x],xmax[ls[x]]);
xmin[x] = min(xmin[x],xmin[ls[x]]);
ymax[x] = max(ymax[x],ymax[ls[x]]);
ymin[x] = min(ymin[x],ymin[ls[x]]);
}
if(rs[x]) {
xmax[x] = max(xmax[x],xmax[rs[x]]);
xmin[x] = min(xmin[x],xmin[rs[x]]);
ymax[x] = max(ymax[x],ymax[rs[x]]);
ymin[x] = min(ymin[x],ymin[rs[x]]);
}
}
int build(int l,int r) {
if(l > r) return 0;
int mid = (l + r) >> 1;
double x1 = 0,xv = 0,y1 = 0,yv = 0;
for(int i = l;i <= r; ++i) {
x1 += s[i].x;
y1 += s[i].y;
}
x1 /= 1. * (r - l + 1);
y1 /= 1. * (r - l + 1);
for(int i = l;i <= r; ++i) {
xv += p2(s[i].x - x1);
yv += p2(s[i].y - y1);
}//找方差
if(xv > yv) nth_element(s + l,s + mid,s + r + 1,cmpx);
else nth_element(s + l,s + mid,s + r + 1,cmpy);//进行划分
ls[mid] = build(l,mid - 1);//注意此处右边界为mid-1
rs[mid] = build(mid + 1,r);
pushup(mid);
return mid;
}
int f(int a,int b) {
return max(p2(s[a].x - xmax[b]),p2(s[a].x - xmin[b])) +
max(p2(s[a].y - ymax[b]),p2(s[a].y - ymin[b]));
}//估价函数
void query(int l,int r,int id) {
if(l > r) return;
int mid = (l + r) >> 1;
int val = p2(s[mid].x - s[id].x) + p2(s[mid].y - s[id].y);
if(val > Q.top()) {
Q.pop();
Q.push(val);
}
int d1 = f(id,ls[mid]),d2 = f(id,rs[mid]);//利用估价函数剪枝
if(d1 > Q.top() && d2 > Q.top()) {
if(d1 > d2) {
query(l,mid - 1,id);
if(d2 > Q.top()) query(mid + 1,r,id);
} else {
query(mid + 1,r,id);
if(d1 > Q.top()) query(l,mid - 1,id);
}
} else {
if(d1 > Q.top()) query(l,mid - 1,id);
if(d2 > Q.top()) query(mid + 1,r,id);
}
}
signed main () {
#ifdef FILE
freopen(".in","r",stdin);
freopen(".out","w",stdout);
#endif
read(n); read(k);
for(int i = 1;i <= n; ++i)
read(s[i].x),read(s[i].y);
k <<= 1;
for(int i = 1;i <= k; ++i) Q.push(0);
build(1,n);
for(int i = 1;i <= n; ++i) query(1,n,i);//对于每一个点,更新小根堆内的值
printf("%lld\n",Q.top());
return 0;
}
咕咕咕
%%%
cxy txdy
丑小鸭挺小的呀