[Violet]天使玩偶/SJY摆棋子
\(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摆棋子的更多相关文章
- bzoj2716/2648 / P4169 [Violet]天使玩偶/SJY摆棋子
P4169 [Violet]天使玩偶/SJY摆棋子 k-d tree 模板 找了好几天才发现输出优化错了....真是zz...... 当子树非常不平衡时,就用替罪羊树的思想,拍扁重建. luogu有个 ...
- 【LG4169】[Violet]天使玩偶/SJY摆棋子
[LG4169][Violet]天使玩偶/SJY摆棋子 题面 洛谷 题解 至于\(cdq\)分治的解法,以前写过 \(kdTree\)的解法好像还\(sb\)一些 就是记一下子树的横.纵坐标最值然后求 ...
- 洛谷 P4169 [Violet]天使玩偶/SJY摆棋子 解题报告
P4169 [Violet]天使玩偶/SJY摆棋子 题目描述 \(Ayu\)在七年前曾经收到过一个天使玩偶,当时她把它当作时间囊埋在了地下.而七年后 的今天,\(Ayu\) 却忘了她把天使玩偶埋在了哪 ...
- luoguP4169 [Violet]天使玩偶/SJY摆棋子 K-Dtree
P4169 [Violet]天使玩偶/SJY摆棋子 链接 luogu 思路 luogu以前用CDQ一直过不去. bzoj还是卡时过去的. 今天终于用k-dtree给过了. 代码 #include &l ...
- 洛谷P4169 [Violet]天使玩偶/SJY摆棋子(CDQ分治)
[Violet]天使玩偶/SJY摆棋子 题目传送门 解题思路 用CDQ分治开了氧气跑过. 将输入给的顺序作为第一维的时间,x为第二维,y为第三维.对于距离一个询问(ax,ay),将询问分为四块,左上, ...
- [Violet]天使玩偶/SJY摆棋子 [cdq分治]
P4169 [Violet]天使玩偶/SJY摆棋子 求离 \((x,y)\) 最近点的距离 距离的定义是 \(|x1-x2|+|y1-y2|\) 直接cdq 4次 考虑左上右上左下右下就可以了-略微卡 ...
- P4169 [Violet]天使玩偶/SJY摆棋子
题目背景 感谢@浮尘ii 提供的一组hack数据 题目描述 Ayu 在七年前曾经收到过一个天使玩偶,当时她把它当作时间囊埋在了地下.而七年后 的今天,Ayu 却忘了她把天使玩偶埋在了哪里,所以她决定仅 ...
- LG4169 [Violet]天使玩偶/SJY摆棋子
题意 Ayu 在七年前曾经收到过一个天使玩偶,当时她把它当作时间囊埋在了地下.而七年后 的今天,Ayu 却忘了她把天使玩偶埋在了哪里,所以她决定仅凭一点模糊的记忆来寻找它. 我们把 Ayu 生活的小镇 ...
- 洛谷P4169 [Violet]天使玩偶/SJY摆棋子
%%%神仙\(SJY\) 题目大意: 一个二维平面,有两种操作: \(1.\)增加一个点\((x,y)\) \(2.\)询问距离\((x,y)\)曼哈顿最近的一个点有多远 \(n,m\le 300 0 ...
- Luogu P4169 [Violet]天使玩偶/SJY摆棋子
传送门 二维平面修改+查询,cdq分治可以解决. 求关于某个点曼哈顿距离(x,y坐标)最近的点——dis(A,B) = |Ax-Bx|+|Ay-By| 但是如何去掉绝对值呢? 查看题解发现假设所有的点 ...
随机推荐
- 【转】maven profile实现多环境打包
作为一名程序员,在开发的过程中,经常需要面对不同的运行环境(开发环境.测试环境.生产环境.内网环境.外网环境等等),在不同的环境中,相关的配置一般不一样,比如数据源配置.日志文件配置.以及一些软件运行 ...
- spring boot在intellij idea下整合mybatis可能遇到的问题
org.apache.ibatis.builder.BuilderException: Wrong namespace. Expected 'com.sc.starry_sky.dao.UserMap ...
- Mysql explain分析sql语句执行效率
mysql优化–explain分析sql语句执行效率 Explain命令在解决数据库性能上是第一推荐使用命令,大部分的性能问题可以通过此命令来简单的解决,Explain可以用来查看SQL语句的执行效 ...
- WebApiTestHelpPage
这是个什么鬼,第一次见到的时候,我也不知道就花几天时间看了下它的代码 在网上搜索WebApiTestHelpPage会出来很多相关页面 但是它们都是介绍怎么用的,要么就是怎么添加注释 它是怎么 ...
- centos7下更新firefox
下载最新版firefox 1.点击三条线-问号-firefox帮助-安装和更新-linux安装-系统和语言下载 保存到指定目录,比如home下 2.解压 tar xjf firefox-*.tar.b ...
- Vue如何使用动态刷新Echarts组件
这次给大家带来Vue如何使用动态刷新Echarts组件,Vue使用动态刷新Echarts组件的注意事项有哪些,下面就是实战案例,一起来看一下. 需求背景:dashboard作为目前企业中后台产品的“门 ...
- js实现链式操作
前言:前不久阿里远程面试时问了我一个问题,如下: function Person(){}; var person = new Person(); //实现person.set(10).get()返回2 ...
- [AngularJS] “路由”的定义概念、使用详解——AngularJS学习资料教程
这是小编的一些学习资料,理论上只是为了自己以后学习需要的,但是还是需要认真对待的 以下内容仅供参考,请慎重使用学习 AngularJS“路由”的定义概念 AngularJS最近真的很火,很多同事啊同学 ...
- atitit.js 与c# java交互html5化的原理与总结.doc
atitit.js 与c# java交互html5化的原理与总结.doc 1. 实现html5化界面的要解决的策略1 1.1. Js交互1 1.2. 动态参数个数1 1.3. 事件监听2 2. sen ...
- Flutter 中 ListView 的使用
这个小例子使用的是豆瓣 API 中 正在上映的电影的开放接口,要实现的主要效果如下: JSON 数据结构 Item 结构 Item 的结构是一个 Card 包含着一个 Row 然后这个 Row 里面左 ...