题目

\(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. linux命令新建文件

    在命令行输入vi filename就创建了一个叫filename的文件了,如果存在就打开了. 进入vi以后,输入内容,最后按一下esc,再按冒号,输入wq就保存退出了. 新建一个文本文件 vi New ...

  2. 湘潭校赛 Bob's Problem

    Bob's Problem Accepted : 18   Submit : 115 Time Limit : 1000 MS   Memory Limit : 65536 KB  题目描述 Bob今 ...

  3. 用正则表达式修改html字符串的所有div的style样式

    最近项目中有一接口返回的一个字段是html格式的字符串,里边每个div中style的高度是固定的px,然后再手机端显示的时候发现,div中的内容重叠了:效果图如下: 对应的div如下: 由于高度固定, ...

  4. 用python实现一个简单的聊天功能,tcp,udp,socketserver版本

    基于tcp协议版本 服务器端 import socket server = socket.socket() server.bind(('127.0.0.1', 8001)) server.listen ...

  5. ASP.NET MVC 简单事务添加

    ASP.NET MVC 简单事务 //实例化查询上下文 using ( BookStoreEntities db = new BookStoreEntities()) { //找到需要价格和名称的数据 ...

  6. cf121C. Lucky Permutation(康托展开)

    题意 题目链接 Sol 由于阶乘的数量增长非常迅速,而\(k\)又非常小,那么显然最后的序列只有最后几位会发生改变. 前面的位置都是\(i = a[i]\).那么前面的可以直接数位dp/爆搜,后面的部 ...

  7. Laravel 多域名共享session

    在网站开发中会涉及登陆的问题,在登陆的过程中为了方便用户体验,我们需要用户在主域名登陆,在其他域名下也要保持登陆状态: 在config/session.php中: 更新网站配置缓存即可

  8. Java基础—注解的使用

    1.注解的概述: 注解是用来替代配置文件的!你回忆一下,我们以前总是要写一些配置文件,例如web.xml你还记得么?里面要写<servlet>和<servlet-mapping> ...

  9. L3(SP+OO+UT)能力评估

  10. Android属性动画简单剖析

    运行效果图: 先看布局文件吧,activity_main.xml: <?xml version="1.0" encoding="utf-8"?> & ...