题目

\(KD-tree\)做最近点对的复杂度好像是假的吧,怎么看也看不出来是\(O(\sqrt{n})\)啊

首先\(KD-tree\)长得和平衡树还是很像的,每个节点都存储了一个\(k\)维空间上的点

但是\(KD-tree\)的每一棵子树都是一个\(k\)维的空间,对于\(2D-tree\)来说就是一个矩形

我们存好这个矩形的内最小和最大的的\(x,y\)坐标,就可以利用这个东西来剪枝了

如果发现询问点和矩形的曼哈顿距离都超过了当前答案,我们就没有必要进入这个子树了

由于这道题还有插入,我们往某一个位置反复插入可能会导致树高过大,于是自闭

可以利用替罪羊的思想,对于一个点\(x\),发现\(max(sz[l[x]],sz[r[x]])>sz[x]\times \alpha\),就说明这个子树很不平衡了,我们就暴力重构一下,\(\alpha\)一般取\(0.65\)到\(0.75\)就好

代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define re register
#define LL long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
const int maxn=1000005;
const int inf=99999999;
const double alph=0.75;
inline int read() {
char c=getchar();int x=0;while(c<'0'||x>'9') c=getchar();
while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
int n,m,cnt,op,ans,top;
int mx[maxn][2],mi[maxn][2],sz[maxn],st[maxn];
int l[maxn],r[maxn];
struct Point{int x[2];}p[maxn],id[maxn];
inline int newNode() {
if(top) return st[top--];
return ++cnt;
}
inline int cmp(Point A,Point B) {return A.x[op]<B.x[op];}
inline void pushup(int k) {
mi[k][0]=mx[k][0]=id[k].x[0];
mi[k][1]=mx[k][1]=id[k].x[1];
for(re int i=0;i<2;i++) {
if(l[k]) mi[k][i]=min(mi[k][i],mi[l[k]][i]),
mx[k][i]=max(mx[k][i],mx[l[k]][i]);
if(r[k]) mi[k][i]=min(mi[k][i],mi[r[k]][i]);
mx[k][i]=max(mx[k][i],mx[r[k]][i]);
}
sz[k]=sz[l[k]]+sz[r[k]]+1;
}
int build(int x,int y,int o) {
if(x>y) return 0;
int now=newNode();
int mid=x+y>>1;
op=o;std::nth_element(p+x,p+mid,p+y+1,cmp);id[now]=p[mid];
l[now]=build(x,mid-1,o^1);r[now]=build(mid+1,y,o^1);
pushup(now);return now;
}
inline int getdis(Point a,int k) {
int res=0;
for(re int i=0;i<2;i++) {
if(a.x[i]>=mi[k][i]&&a.x[i]<=mx[k][i]) continue;
if(a.x[i]<=mi[k][i]) res+=mi[k][i]-a.x[i];
else if(a.x[i]>=mx[k][i]) res+=a.x[i]-mx[k][i];
}
return res;
}
inline int dis(Point a,Point b) {return abs(a.x[0]-b.x[0])+abs(a.x[1]-b.x[1]);}
void query(Point now,int k) {
ans=min(ans,dis(now,id[k]));
int dl=inf,dr=inf;
if(l[k]) dl=getdis(now,l[k]);
if(r[k]) dr=getdis(now,r[k]);
if(dl<dr) {
if(dl<ans) query(now,l[k]);
if(dr<ans) query(now,r[k]);
}
else {
if(dr<ans) query(now,r[k]);
if(dl<ans) query(now,l[k]);
}
}
inline void del(int x) {
if(l[x]) del(l[x]);
st[++top]=x;p[++n]=id[x];
if(r[x]) del(r[x]);
}
inline int check(int k,int o) {
if(max(sz[l[k]],sz[r[k]])>sz[k]*alph) {
n=0,del(k);
return build(1,n,o);
}
return k;
}
int ins(int k,int now,int o) {
if(!k) {
k=newNode();
id[k]=p[now];pushup(k);
return k;
}
if(p[now].x[o]<=id[k].x[o]) l[k]=ins(l[k],now,o^1);
else r[k]=ins(r[k],now,o^1);
pushup(k);return check(k,o);
}
int main() {
n=read(),m=read();
for(re int i=1;i<=n;i++) p[i].x[0]=read(),p[i].x[1]=read();
build(1,n,0);int opt,x,y;
while(m--) {
opt=read(),x=read(),y=read();
if(opt==2) {
ans=inf;Point now;
now.x[0]=x,now.x[1]=y;
query(now,1);
printf("%d\n",ans);
}
if(opt==1) {
p[++n].x[0]=x,p[n].x[1]=y;
ins(1,n,0);
}
}
return 0;
}

[Violet]天使玩偶/SJY摆棋子的更多相关文章

  1. bzoj2716/2648 / P4169 [Violet]天使玩偶/SJY摆棋子

    P4169 [Violet]天使玩偶/SJY摆棋子 k-d tree 模板 找了好几天才发现输出优化错了....真是zz...... 当子树非常不平衡时,就用替罪羊树的思想,拍扁重建. luogu有个 ...

  2. 【LG4169】[Violet]天使玩偶/SJY摆棋子

    [LG4169][Violet]天使玩偶/SJY摆棋子 题面 洛谷 题解 至于\(cdq\)分治的解法,以前写过 \(kdTree\)的解法好像还\(sb\)一些 就是记一下子树的横.纵坐标最值然后求 ...

  3. 洛谷 P4169 [Violet]天使玩偶/SJY摆棋子 解题报告

    P4169 [Violet]天使玩偶/SJY摆棋子 题目描述 \(Ayu\)在七年前曾经收到过一个天使玩偶,当时她把它当作时间囊埋在了地下.而七年后 的今天,\(Ayu\) 却忘了她把天使玩偶埋在了哪 ...

  4. luoguP4169 [Violet]天使玩偶/SJY摆棋子 K-Dtree

    P4169 [Violet]天使玩偶/SJY摆棋子 链接 luogu 思路 luogu以前用CDQ一直过不去. bzoj还是卡时过去的. 今天终于用k-dtree给过了. 代码 #include &l ...

  5. 洛谷P4169 [Violet]天使玩偶/SJY摆棋子(CDQ分治)

    [Violet]天使玩偶/SJY摆棋子 题目传送门 解题思路 用CDQ分治开了氧气跑过. 将输入给的顺序作为第一维的时间,x为第二维,y为第三维.对于距离一个询问(ax,ay),将询问分为四块,左上, ...

  6. [Violet]天使玩偶/SJY摆棋子 [cdq分治]

    P4169 [Violet]天使玩偶/SJY摆棋子 求离 \((x,y)\) 最近点的距离 距离的定义是 \(|x1-x2|+|y1-y2|\) 直接cdq 4次 考虑左上右上左下右下就可以了-略微卡 ...

  7. P4169 [Violet]天使玩偶/SJY摆棋子

    题目背景 感谢@浮尘ii 提供的一组hack数据 题目描述 Ayu 在七年前曾经收到过一个天使玩偶,当时她把它当作时间囊埋在了地下.而七年后 的今天,Ayu 却忘了她把天使玩偶埋在了哪里,所以她决定仅 ...

  8. LG4169 [Violet]天使玩偶/SJY摆棋子

    题意 Ayu 在七年前曾经收到过一个天使玩偶,当时她把它当作时间囊埋在了地下.而七年后 的今天,Ayu 却忘了她把天使玩偶埋在了哪里,所以她决定仅凭一点模糊的记忆来寻找它. 我们把 Ayu 生活的小镇 ...

  9. 洛谷P4169 [Violet]天使玩偶/SJY摆棋子

    %%%神仙\(SJY\) 题目大意: 一个二维平面,有两种操作: \(1.\)增加一个点\((x,y)\) \(2.\)询问距离\((x,y)\)曼哈顿最近的一个点有多远 \(n,m\le 300 0 ...

  10. Luogu P4169 [Violet]天使玩偶/SJY摆棋子

    传送门 二维平面修改+查询,cdq分治可以解决. 求关于某个点曼哈顿距离(x,y坐标)最近的点——dis(A,B) = |Ax-Bx|+|Ay-By| 但是如何去掉绝对值呢? 查看题解发现假设所有的点 ...

随机推荐

  1. 【转】手机web前端调试页面的几种方式

    前言 PC端web页面调试比较容易,这里主要说几种移动端调试的方法,从简单到复杂.从模拟调试到远程调试,大概分为几部分: 1.Chrome DevTools(谷歌浏览器)的模拟手机调试 2.weinr ...

  2. Mac下显示和隐藏隐藏文件的命令

    打开终端,输入: 1.defaults write com.apple.finder AppleShowAllFiles -bool true 此命令显示隐藏文件defaults write com. ...

  3. Spring学习手札(四)谈谈Spring Bean的生命周期及作用域

    在Spring中,那些组成应用程序的主体以及由Spring IoC容器所管理的对象,被称之为Bean.Bean与应用程序中其他对象(比如自己创建类)的区别就是,Bean是由IoC容器创建于销毁的.在S ...

  4. 在AE二次开发中出“正试图在 OS 加载程序锁内执行托管代码。不要尝试在 DllMain 或映像初始化函数内运行托管代码,这样做会导致应用程序挂起。”异常解决方案

    今天的一个项目总用到了AE的开发组件,也就是ESRI公司提供的一系列的开发包(组件)都是以dll(动态链接库的形式)然后今天在调试的时候却出现了“正试图在 OS 加载程序锁内执行托管代码.不要尝试在 ...

  5. angularjs ui-view多视口多层嵌套路由配置

    最近研究了一下ui-view多层嵌套,整理了一下 1.最简单的ui-view用法 html部分: <ul class="nav navbar-nav"> <li ...

  6. HBuilder开发App Step1——环境搭建,HelloMUI 以及真机调试

    No1. 必须搭建java环境 只需要最基础的java环境,也就是cmd下可以运行java和javac即可, 具体教程请自行百度,都会有很详细的教程,这里不重点介绍. No2. 下载安装HBuilde ...

  7. 原生爬虫小Demo

    import re from urllib import request class Spider(): url = 'https://www.panda.tv/cate/lol' #[\s\S]匹配 ...

  8. Eclipse工程 导入 Android Studio

    最近Eclipse好多项目转Android Studio 百度翻看好多文章 这篇不错 特纪录下 地址:http://www.cnblogs.com/bluestorm/p/3757402.html 一 ...

  9. ArcGis实现画矩形(RectangleFeedBack)

    private void axMapControl1_OnMouseDown(object sender, IMapControlEvents2_OnMouseDownEvent e)         ...

  10. jedis spring集成

    jedis spring集成把jedis的核心对象交给spring管理.jedis核心对象:配置文件.连接池配置对象.连接池.集成方式有两种:spring-data-redis:自己封装 前提:要有一 ...