【bzoj2961】共点圆 k-d树
更新:此题我的代码设置eps=1e-8会WA,现在改为1e-9貌似T了
此题网上的大部分做法是cdq分治+凸包,然而我觉得太烦了,于是自己口胡了一个k-d树做法:
加入一个圆$(x,y)$,直接在k-d树上加入这个点即可,注意要打rebuild否则会T。
查询一个点$(x_0,y_0)$是否在所有的圆上时:
我们设当前需要判断一个圆$(x,y)$是否覆盖该点,通过简单的分析,可以列出以下式子:
$(x-x_0)^2+(y-y_0)^2≤x_0^2+y_0^2$
我们不妨设$y_0>0$通过简单变式和移项,我们可以得到:
$y \geq -\frac{x_0}{y_0}x+\frac{x_0^2+y_0^2}{2y}$
我们将$ -\frac{x_0}{y_0} $和$ \frac{x_0^2+y_0^2}{2y} $视作常数,得到$y≤kx+b$,这是啥?一个半平面啊!!
问题即转化为了当前k-d树中是否所有点均在该半平面内,直接在k-d树中查询即可(实际上还需要有点思考量的分类讨论)
对于$y_0<0$的情况,部分符号需做些许更改。对于$y_0=0$的情况,需要特殊讨论!!(大概是$x<\frac{x_0}{2}$)
然后就没啦,时间复杂度$O(n log n+n^{1.5})$
PS:千万要记得打y=0的情况(我就被这个卡了很久)
#include<bits/stdc++.h>
#define M 500000
#define eps 1e-9
#define INF 1e20
using namespace std; #define MFLONG 13000000
#define NUM(x) ((48<=x&&x<=57)||x=='-')
char _c[MFLONG],_w[MFLONG]={};int _ns=,_nw=;int _x[],_ld;
inline void rd(int &_q){int _fu;if(_c[_ns]==) return;while(!NUM(_c[_ns])) _ns++;if(_c[_ns]=='-') _fu=-,_ns++;else _fu=;_q=;while(NUM(_c[_ns])) _q=_q*+_c[_ns++]-;_q=_fu*_q;}
inline void rd(double &X)
{
double x=,f=;
for (;_c[_ns]<''||_c[_ns]>'';_ns++) if (_c[_ns]=='-') f=-;
for (;_c[_ns]>=''&&_c[_ns]<='';_ns++) x=x*+_c[_ns]-'';
if (_c[_ns]!='.') {X=x*f;return;} _ns++;
for (double hh=0.1;_c[_ns]>=''&&_c[_ns]<='';_ns++,hh=hh/) x+=(_c[_ns]-'')*hh;
X=x*f;
} int D;
struct node{
double max[],min[],a[];
int l,r,siz;
node(){
max[]=max[]=a[]=a[]=l=r=siz=;
min[]=min[]=INF;
}
void clear(){
max[]=max[]=a[]=a[]=l=r=siz=;
min[]=min[]=INF;
}
node(double x,double y){
max[]=max[]=l=r=siz=;
min[]=min[]=INF;
a[]=x; a[]=y;
}
friend bool operator <(node a,node b){return a.a[D]<b.a[D];}
}a[M]; int root=,use=,reb=,rebfa=,rebd=; void insert(int &x,int fa,int d,node k){
if(!x){x=++use; a[x]=k;}
else{
if(k.a[d]<a[x].a[d]) insert(a[x].l,x,d^,k);
else insert(a[x].r,x,d^,k);
}
a[x].siz++;
a[x].max[]=max(a[x].max[],k.a[]); a[x].min[]=min(a[x].min[],k.a[]);
a[x].max[]=max(a[x].max[],k.a[]); a[x].min[]=min(a[x].min[],k.a[]);
if(max(a[a[x].l].siz,a[a[x].r].siz)>a[x].siz*0.77) reb=x,rebfa=fa,rebd=d;
} int id[M]={},cnt=;
bool cmp(int x,int y){return a[x]<a[y];}
void bl(int x){if(!x) return;id[++cnt]=x;bl(a[x].l); bl(a[x].r);}
void rebuild(int &x,int l,int r,int d){
if(l>r) {x=; return;}
int mid=(l+r)>>; D=d;
nth_element(id+l,id+mid,id+r+,cmp); x=id[mid];
a[x].max[]=a[x].min[]=a[x].a[];
a[x].max[]=a[x].min[]=a[x].a[];
rebuild(a[x].l,l,mid-,d^); rebuild(a[x].r,mid+,r,d^);
a[x].siz=a[a[x].l].siz+a[a[x].r].siz+;
for(int i=;i<;i++)
a[x].max[i]=max(a[x].max[i],max(a[a[x].l].max[i],a[a[x].r].max[i])),
a[x].min[i]=min(a[x].min[i],min(a[a[x].l].min[i],a[a[x].r].min[i]));
}
void rebuild(){
if(!reb) return;
bl(reb);
if(!rebfa) rebuild(root,,cnt,rebd);
else{
if(a[rebfa].l==reb) rebuild(a[rebfa].l,,cnt,rebd);
else rebuild(a[rebfa].r,,cnt,rebd);
}
cnt=reb=rebfa=;
} bool queryl(int x,double k,double b){
if(!x) return ;
if(k>&&a[x].max[]*k+b<a[x].min[]-eps) return ;
if(k>&&a[x].min[]*k+b>=a[x].max[]) return ;
if(k>&&a[x].a[]*k+b<a[x].a[]+eps) return ; if(k<=&&a[x].max[]*k+b>=a[x].max[]-eps) return ;
if(k<=&&a[x].min[]*k+b<a[x].min[]) return ;
if(k<=&&!(a[x].a[]*k+b>a[x].a[]-eps)) return ; return queryl(a[x].l,k,b)&queryl(a[x].r,k,b);
} bool queryr(int x,double k,double b){
if(!x) return ;
if(k>&&a[x].max[]*k+b<a[x].min[]) return ;
if(k>&&a[x].min[]*k+b>a[x].max[]-eps) return ;
if(k>&&a[x].a[]*k+b>a[x].a[]-eps) return ; if(k<=&&a[x].max[]*k+b>a[x].max[]) return ;
if(k<=&&a[x].min[]*k+b<a[x].min[]+eps) return ;
if(k<=&&!(a[x].a[]*k+b<a[x].a[]+eps)) return ; return queryr(a[x].l,k,b)&queryr(a[x].r,k,b);
} bool queryx(int x,int k,double l){
if(!x) return ;
if(k>&&l<=a[x].min[]+eps) return ;
if(k>&&l>a[x].max[]-eps) return ;
if(k>&&l>a[x].a[]-eps) return ; if(k<&&a[x].max[]-eps<=l) return ;
if(k<&&l<a[x].min[]+eps) return ;
if(k<&&l>a[x].a[]) return ; return queryx(a[x].l,k,l)&queryx(a[x].r,k,l);
} int main(){
//fread(_c,1,MFLONG,stdin);
int n; //rd(n);
scanf("%d",&n);
while(n--){
int op; double x,y;
//rd(op);rd(x);rd(y);
scanf("%d%lf%lf",&op,&x,&y);
if(op==){
insert(root,,,node(x,y));
rebuild();
}else{
if(fabs(y)<=eps&&fabs(x)<=eps){
printf("Yes\n");
continue;
}
if(fabs(y)<eps){
bool ck=queryx(root,(x>?:-),(x*x)/x/.);
if(ck&&use) puts("Yes"); else puts("No");
continue;
}
bool ck; double k,b;
b=(x*x+y*y)/(*y); k=-x/y;
if(y<) ck=queryl(root,k,b);
else ck=queryr(root,k,b);
if(ck&&use) puts("Yes"); else puts("No");
}
}
}
【bzoj2961】共点圆 k-d树的更多相关文章
- BZOJ2961 共点圆[CDQ分治]
题面 bzoj 其实就是推一下圆的式子 长成这个样子 假设要查询的点是(x, y) 某个圆心是(p, q) \((x - p)^2 + (y - q)^2 \leq p^2 + q^2\) 变成 \( ...
- bzoj2961 共点圆 (CDQ分治, 凸包)
/* 可以发现可行的圆心相对于我们要查询的点是在一个半平面上, 然后我们要做的就是动态维护凸壳然后用这个半平面去切它 看看是否是在合法的那一面 然后cdq分治就可以了 代码基本是抄的, */ #inc ...
- BZOJ2961: 共点圆(CDQ分治+凸包)
题面 传送门 题解 这题解法真是多啊--据说可以圆反演转化为动态插入半平面并判断给定点是否在半平面交中,或者化一下改成给定点判断是否所有点都在某一个半平面内-- 鉴于圆反演我也不会,这里讲一下直接推的 ...
- [BZOJ2961] 共点圆 [cdq分治+凸包]
题面 BZOJ传送门 思路 首先考虑一个点$(x_0,y_0)$什么时候在一个圆$(x_1,y_1,\sqrt{x_1^2+y_1^2})$内 显然有:$x_1^2+y_1^2\geq (x_0-x_ ...
- BZOJ2961: 共点圆
好久没发了 CDQ分治,具体做法见XHR的论文… /************************************************************** Problem: 29 ...
- bzoj2961 共点圆 bzoj 4140
题解: 比较水的一道题 首先我们化简一下式子发现是维护xxo+yyo的最值 显然是用凸包来做 我们可以直接用支持插入删除的凸包 也是nlogn的 因为没有强制在线,我们也可以cdq,考虑前面一半对答案 ...
- [BZOJ2961]共点圆-[凸包+cdq分治]
Description 传送门 Solution 考虑对于每一个点: 设圆的坐标为(x,y),点的坐标为(x0,y0).依题意得,当一个点在圆里,需要满足(x-x0)2+(y-y0)2<=x2+ ...
- 【BZOJ2961】共点圆(CDQ分治)
[BZOJ2961]共点圆(CDQ分治) 题面 BZOJ 题解 设询问点\((x,y)\),圆心是\((X,Y)\) 那么如果点在园内的话就需要满足 \((X-x)^2+(Y-y)^2\le X^2+ ...
- 【BZOJ4140】共点圆加强版(二进制分组)
[BZOJ4140]共点圆加强版(二进制分组) 题面 BZOJ 题解 我卡精度卡了一天.... 之前不强制在线的做法是\(CDQ\)分治,维护一个凸壳就好了. 现在改成二进制分组,每次重建凸壳就好了. ...
- HDU 2157 How many ways??:矩阵快速幂【i到j共经过k个节点的方法数】
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2157 题解: 给你一个有向图,n个节点m条边,问你从i到j共经过k个节点的方法数(不算i点). 题解: ...
随机推荐
- MySQL之练习题5
.将所有的课程的名称以及对应的任课老师姓名打印出来,如下: SELECT cname,tname FROM course INNER JOIN teacher WHERE course.teacher ...
- 第一章:模型层model layer
1.模型和字段 (1)基本的原则如下: 每个模型在Django中的存在形式为一个Python类 每个模型都是django.db.models.Model的子类 模型的每个字段(属性)代表数据表的某一列 ...
- py-函数进阶
名称空间 又名name space, 顾名思义就是存放名字的地方,存什么名字呢?举例说明,若变量x=1,1存放于内存中,那名字x存放在哪里呢?名称空间正是存放名字x与1绑定关系的地方 名称空间共3种, ...
- 对于Serializable id类型的数据的测试
今天编写了一个这样的例子,然后进行了Junit测试,但是发现类型总是不匹配,最后测出如下 public <T> void deleteEntry(Class<T> t, Ser ...
- Series转成list
直接list(series)就可以的 最佳的方式是将列表转换成Python中的科学计算包numpy包的array类型,再进行加减. 1 2 3 4 import numpy as np a = np. ...
- 201709021工作日记--Volley源码详解(五)
学习完了CacheDispatcher这个类,下面我们看下NetworkDispatcher这个类的具体细节,先上代码: /** * 提供一个线程执行网络调度的请求分发 * Provides a th ...
- (深搜)Sum It Up -- poj --1564
链接: http://poj.org/problem?id=1564 http://acm.hust.edu.cn/vjudge/contest/view.action?cid=88230#probl ...
- node 问题
安装:使用.msi直接安装就好,环境变量已经设置好了 1.问题:验证node是否正确安装 办法:直接计算1+1:创建服务器. 在项目文件夹的路径下,输入node命令,会看到一个提示符,这里只能输入直接 ...
- EBS FORM 编译
http://www.cnblogs.com/quanweiru/archive/2013/01/01/2841574.html EBS R11============================ ...
- Android-Xml,PullParser,解析
在上一篇博客,Android-XML格式描述,介绍来XML在Android中的格式: 解析persons.xml文件内容: <?xml version="1.0" encod ...