【BZOJ2961】共点圆(CDQ分治)

【BZOJ2961】共点圆(CDQ分治)

题面

BZOJ

题解

设询问点\((x,y)\),圆心是\((X,Y)\)
那么如果点在园内的话就需要满足
\((X-x)^2+(Y-y)^2\le X^2+Y^2\)
拆开之后就变成了
\(x^2+y^2-2xX\le 2yY\)
除过去就是\(-\frac{x}{y}X+\frac{x^2+y^2}{2y}\le Y\)
显然左边是一个直线,那么,这个式子的含义就是,
对于任意\((X,Y)\),在\(X\)处的函数值都要小于\(Y\)
即这个直线在所有的圆心下方。
那么维护一下下凸壳,每次拿斜率去切凸壳,检查一下截距就好了。
当然,上面是假装\(y>0\),如果\(y<0\)的话需要变号,变成了所有圆心都在直线的下方了
这里需要维护一个上凸壳。
\(CDQ\)分治就可以很好的维护这些东西了。
然而我这个傻逼这都不会写

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
#define ll long long
#define MAX 500500
#define Sqr(x) ((x)*(x))
const double eps=1e-8;
struct Opt{int op,id;double x,y,k;}p[MAX],tmp[MAX],S1[MAX],S2[MAX];
bool operator<(Opt a,Opt b){return a.k<b.k;}
bool cmp(Opt a,Opt b){return a.id<b.id;}
double Slope(Opt a,Opt b)
{
	if(fabs(a.x-b.x)<eps)return a.y<b.y?1e18:-1e18;
	return (a.y-b.y)/(a.x-b.x);
}
double Dis(Opt a,Opt b){return sqrt(Sqr(a.x-b.x)+Sqr(a.y-b.y));}
bool ans[MAX];
int n;
void CDQ(int l,int r)
{
	if(l==r)return;
	int mid=(l+r)>>1,t1=l,t2=mid+1,tp1=0,tp2=0;
	for(int i=l;i<=r;++i)
		if(p[i].id<=mid)tmp[t1++]=p[i];
		else tmp[t2++]=p[i];
	for(int i=l;i<=r;++i)p[i]=tmp[i];
	CDQ(l,mid);
	for(int i=l;i<=mid;++i)
	{
		if(p[i].op)continue;
		while(tp1>1&&Slope(S1[tp1-1],p[i])+eps>Slope(S1[tp1-1],S1[tp1]))--tp1;S1[++tp1]=p[i];
		while(tp2>1&&Slope(S2[tp2-1],p[i])-eps<Slope(S2[tp2-1],S2[tp2]))--tp2;S2[++tp2]=p[i];
	}
	t1=tp1,t2=1;
	for(int i=mid+1;i<=r;++i)
	{
		if(!p[i].op)continue;
		if(p[i].y<0)
		{
			while(t1>1&&Slope(S1[t1-1],S1[t1])<p[i].k)--t1;
			if(t1>0&&Dis(S1[t1],S1[0])<Dis(S1[t1],p[i]))ans[p[i].id]=false;
		}
		else
		{
			while(t2<tp2&&Slope(S2[t2],S2[t2+1])<p[i].k)++t2;
			if(t2<=tp2&&Dis(S2[t2],S2[0])<Dis(S2[t2],p[i]))ans[p[i].id]=false;
		}
	}
	CDQ(mid+1,r);
	t1=l;t2=mid+1;
	for(int i=l;i<=r;++i)
		if(t2>r||(t1<=mid&&p[t1].x<p[t2].x))tmp[i]=p[t1++];
		else tmp[i]=p[t2++];
	for(int i=l;i<=r;++i)p[i]=tmp[i];
}
int main()
{
	freopen("2961.in","r",stdin);
	freopen("2961.out","w",stdout);
	ios::sync_with_stdio(false);
	cin>>n;
	for(int i=1,opt,sum=0;i<=n;++i)
	{
		double x,y;
		cin>>opt>>x>>y;
		if(opt==0)p[i]=(Opt){0,i,x,y,0},++sum;
		else p[i]=(Opt){1,i,x,y,0};
		if(fabs(y)>eps)p[i].k=-x/y;else p[i].k=1e18;
		if(opt==1)ans[i]=(bool)sum;
	}
	sort(&p[1],&p[n+1]);CDQ(1,n);
	sort(&p[1],&p[n+1],cmp);
	for(int i=1;i<=n;++i)if(p[i].op)puts(ans[i]?"Yes":"No");
	return 0;
}


posted @ 2018-08-13 09:49  小蒟蒻yyb  阅读(446)  评论(0编辑  收藏  举报