KDtree是一种很优秀的暴力(实质上也是线段树)
可以解决:n维k远点对问题
有些需要CDQ分治的难题,用KDtree就可以解决了(思维难度较小)
经典例题:天使玩偶
KDtree
CDQ分治
实测KDtree较快,然而dalao好像都不喜欢用这种暴力做法,都是推荐CDQ
然而蒟蒻就有蒟蒻的方法,暴力什么的先稳住再说
找到了KDtree的复杂度分析:
构建: O(log2n) O ( l o g 2 n )
插入:O(logn) 插 入 : O ( l o g n )
删除:O(logn) 删 除 : O ( l o g n )
查询:O(n1−1/k+m) 查 询 : O ( n 1 − 1 / k + m ) m—每次要搜索的最近点个数
下面的代码普适性更高,可以扩展到任意维度
(给出的是最近点对的代码,如果想求k远点对,我们只要开一个优先队列记录一下就好了,只有队列不满或者当前dis小于队首元素我们才进行这个方向的检索,值得注意的是:priority_queue是大根堆)
const int INF=0x33333333;
const int N=1000010;
const int o=2;
struct node{
int d[o]; //根结点坐标
int mn[o];
int mx[o];
int l,r,dis;
bool operator <(const node &a) const{
return dis<a.dis;
}
}t[N];
int x[o],n,m,root,ans;
void update(int x) {
int lc=t[x].l;
int rc=t[x].r;
if (lc) {
for (int i=0;i<o;i++) {
t[x].mn[i]=min(t[x].mn[i],t[lc].mn[i]);
t[x].mx[i]=max(t[x].mx[i],t[lc].mx[i]);
}
}
if (rc) {
for (int i=0;i<o;i++) {
t[x].mn[i]=min(t[x].mn[i],t[rc].mn[i]);
t[x].mx[i]=max(t[x].mx[i],t[rc].mx[i]);
}
}
}
int build(int l,int r,int D) {
int mid=(l+r)>>1;
for (int i=l;i<=r;i++) t[i].dis=t[i].d[D]; //比较标志
nth_element(t+l,t+mid+1,t+r+1); //l~r中排名为mid的元素放在mid位置上
for (int i=0;i<o;i++)
t[mid].mn[i]=t[mid].mx[i]=t[mid].d[i];
if (l!=mid) t[mid].l=build(l,mid-1,(D+1)%o);
if (r!=mid) t[mid].r=build(mid+1,r,(D+1)%o);
update(mid);
return mid;
}
//t[n].mn[i]=t[n].mx[i]=t[n].d[i]=x[i];
void insert(int p) { //插入一个单点代表的区间
int D,now;
D=0,now=root;
while (1) {
for (int i=0;i<o;i++) {
t[now].mn[i]=min(t[now].mn[i],t[p].mn[i]);
t[now].mx[i]=max(t[now].mx[i],t[p].mx[i]);
}
if (t[p].d[D]>=t[now].d[D]) {
if (!t[now].r) {
t[now].r=p;
return;
}
else now=t[now].r;
}
else {
if (!t[now].l) {
t[now].l=p;
return;
}
else now=t[now].l;
}
D=(D+1)%o;
}
}
int dis(int p) {
int d=0;
for (int i=0;i<o;i++) {
if (x[i]<t[p].mn[i]) d+=(t[p].mn[i]-x[i]);
if (x[i]>t[p].mx[i]) d+=(x[i]-t[p].mx[i]);
}
return d;
}
void ask(int now) {
int d0=0,dl,dr;
for (int i=0;i<o;i++) d0+=abs(t[now].d[i]-x[i]);
ans=min(ans,d0);
if (t[now].l) dl=dis(t[now].l);
else dl=INF;
if (t[now].r) dr=dis(t[now].r);
else dr=INF;
if (dl<dr) {
if (dl<ans) ask(t[now].l);
if (dr<ans) ask(t[now].r);
}
else {
if (dr<ans) ask(t[now].r);
if (dl<ans) ask(t[now].l);
}
}