题目

\(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. MFC动态时间表示法——strtime函数

    %a 星期几的简写 %A 星期几的全称 %b 月分的简写 %B 月份的全称 %c 标准的日期的时间串 %C 年份的后两位数字 %d 十进制表示的每月的第几天 %D 月/天/年 %e 在两字符域中,十进 ...

  2. Oracle ORA12514 监听程序当前无法识别连接描述符中请求的服务

    在连接数据库的时候,有时会遇到一个“ORA12514:监听程序当前无法识别连接描述符中请求的服务”的错误,这个错误其实就是数据库动态注册(关于动态注册会在稍后讲解)不生效,导致监听器无法识别客户端连接 ...

  3. 使用CSS3改变文本选中的默认颜色——张鑫旭

    关于浏览器文字选中颜色 以我的系统举例(xp 默认主题),浏览器上页面文字选中后默认的背景色是一种蓝色, 不同浏览器的颜色有些许差异,但大致相同,文字颜色也近乎白色,如下图所示,截自Firefox3. ...

  4. 常用数据库validationQuery语句

    validationQuery是用来验证数据库连接的查询语句,这个查询语句必须是至少返回一条数据的SELECT语句.每种数据库都有各自的验证语句,下表中收集了几种常见数据库的validationQue ...

  5. drupal7 判断用户是否具有某个权限

    user_access() 具体用法可参考http://www.drupalla.com/node/857

  6. 网络I/O模型--04非阻塞模式(解除accept()、 read()方法阻塞)的基础上加入多线程技术

    由于应用程序级别并没有使用多线程技术,这就导致了应用程序只能一个一个地对Socket 套接字进行处理.这个 Socket 套接宇没有处理完,就没法处理下一个 Socket 套接字 .针对这个 问题还是 ...

  7. vue图片上传及java存储图片(亲测可用)

    1.前言 在使用elementui的upload组件时,我一直无法做到上传的图片和其他数据一起提交.单纯的上传文件,java的存储图片的方式也有局限性. 我知道的后端保存图片有两种方式:一种是直接存储 ...

  8. alter system register的用法

    转自 http://blog.csdn.net/njyxfw/article/details/7516143 今天一个同事问到我,有没动态注册监听的命令,查了下,找到了alter system reg ...

  9. 深入理解abstract class和interface

    摘自:http://www.ibm.com/developerworks/cn/java/l-javainterface-abstract/ (如有侵权,请留言,版主将立即删除) abstract c ...

  10. [转]How do you build a database?

    非常简短的文字,却异常明了的说明了一个数据库管理系统的核心原理,原文来自原文. Its a great question, and deserves a long answer. Most datab ...