【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点). 题解: ...
随机推荐
- QQ绝招
1.让QQ头像永远在前 打开"个人设定"窗口,然后在自己的昵称前点一下鼠标,再按空格键插入一两个空格(不能太多了,要不然昵称就不能完整显示了),然后点击"修改" ...
- 2018.10.15 loj#6013. 「网络流 24 题」负载平衡(费用流)
传送门 费用流sb题. 直接从sss向每个点连边,容量为现有物品量. 然后从ttt向每个点连边,容量为最后库存量. 由于两个点之间可以互相任意运送物品,因此相邻的直接连infinfinf的边就行了. ...
- 2018.09.27 bzoj4300: 绝世好题(二进制dp)
传送门 简单dp. 根据题目的描述. 如果数列bn{b_n}bn合法. 那么有:bi−1b_{i-1}bi−1&bi!=0b_i!=0bi!=0,因此我们用f[i]f[i]f[i]表示数 ...
- 第1章 (名词)Le nom
★名词的种类:(1)普通名词 —专有名词,如: un livre —la Chine(2)可数名词—不可数名词,如: un ami —le lait(3)具体名词— ...
- git分支删除
1.列出本地分支: git branch 2.删除本地分支: git branch -D BranchName 其中-D也可以是--delete,如: git branch --delete Bran ...
- python创建二维数组
c=[[0]*3 for i in range(3)] c=[[0 for i in range(3)] for i in range(3)]
- LDA汇总
1.Blei的LDA代码(C):http://www.cs.princeton.edu/~blei/lda-c/index.html2.D.Bei的主页:http://www.cs.princeton ...
- html5获取经纬度
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- NSDictionary NSMutableDictionary NSSet NSMutableSet
//description只是返回了一个字符串 // [person description]; // //如果想要打印需要NSLog // NSLog(@"%@& ...
- ROS教程
Learning ROS 学习ROS Depending on your learning style and preferences, you can take two approaches to ...