bzoj2961-共点圆

题目

(n)次操作,每次加入一个以((x,y))为圆心,经过原点的圆,或者询问一个点是否在所有圆中(包括圆周)。(nle 5 imes 10^5)

分析

这题有两种做法,可以直接推或者运用反演。

方法一

设一个圆的圆心为((a,b)), 一个询问点为((x,y)),那么((x,y))在圆内或圆周上的条件是:

[egin{aligned} (x-a)^2+(y-b)^2le a^2+b^2 \ x^2+y^2le 2ax+2by \ bge -frac{x}{y}a+frac{x^2+y^2}{2y} end{aligned} ]

也就是说,若一个询问点在之前的所有圆中,那么对于每个圆心((a,b))都满足这条式子,而这个式子是一个明显的半平面形式,即问题变成了,每次加入圆的时候其实是加入一个圆心点,询问变成是否所有点都在一条直线的上方。我们对操作分治,变成每次把左边的点加进去,判断右边的询问是否满足。由于所有询问都是点在直线上方问题,所以我们可以对点维护下凸包,二分斜率,看看那一个点是否在下面即可。复杂度为(O(nlog ^2 n))

方法二

所有的圆都经过同一个点——原点!考虑圆反演,那么我们会得到很多直线,一个点在圆外也就是这个点反演后在直线的上方(这题中圆心都在x轴上方)。这样问题就变成了是否每个点都被所有半平面包含。这个可以通过求半平面交再三分,二分,或排序之类的得到。复杂度也为(O(nlog ^2 n)),但是询问的主体是不一样的 。

代码

这是方法一的代码,方法二并没有写。

#include<bits/stdc++.h>
#define P(x) ((x)*(x))
using namespace std;
const int maxn=5e5+1;
struct node {
	double x,y;
	double at,dt;
	inline double operator * (const node a) const {return x*a.y-y*a.x;}
	inline node operator - (const node a) const {return (node){x-a.x,y-a.y};}
	inline bool operator != (const node a) const {return x!=a.x || y!=a.y;}
};
struct Q {
	int o;
	node d;
} b[maxn];
int much[maxn];
bool ans[maxn];
node sta[maxn],bas;
int top;
double sp[maxn],at[maxn],dt[maxn];
inline double dist(node a,node b) {return P(a.x-b.x)+P(a.y-b.y);}
inline bool cmp(node a,node b) {
	return a.at==b.at?a.dt<b.dt:a.at<b.at;
}
void conv(node a[],int sz) {
	if (sz==1) {
		sta[top=1]=a[0];
		return;
	}
	for (int i=1;i<sz;++i) if (a[i].x<a[0].x || (a[i].x==a[0].x && a[i].y>a[0].y)) swap(a[i],a[0]);
	bas=a[0];
	for (int i=1;i<sz;++i) a[i].at=atan2(a[i].y-bas.y,a[i].x-bas.x),a[i].dt=dist(a[i],bas);
	sort(a+1,a+sz,cmp);
	sta[top=1]=a[0];
	for (int i=1;i<sz;++i) if (a[i].x>=sta[top].x && a[i]!=sta[top]) {
		node &nd=a[i];
		while (top>1 && (nd-sta[top-1])*(sta[top]-sta[top-1])>0) --top;
		sta[++top]=nd;
	}
	for (int i=1;i<top;++i) sp[i]=(sta[i+1].y-sta[i].y)/(sta[i+1].x-sta[i].x);
}
void solve(int l,int r) {
	if (l==r) return;
	int mid=(l+r)>>1;
	solve(l,mid);
	solve(mid+1,r);
	static node a[maxn];
	int m=0;
	for (int i=l;i<=mid;++i) if (!b[i].o) a[m++]=b[i].d;
	if (!m) return;
	conv(a,m);
	for (int i=mid+1;i<=r;++i) if (b[i].o) {
		node &nd=b[i].d;
		double k=-nd.x/nd.y;
		int p=upper_bound(sp+1,sp+top,k)-sp;
		ans[i]&=(P(nd.x)+P(nd.y)<=2*(sta[p].x*nd.x+sta[p].y*nd.y));
	}
}
int main() {
#ifndef ONLINE_JUDGE
	freopen("test.in","r",stdin);
#endif
	int n;
	scanf("%d",&n);
	for (int i=1;i<=n;++i) scanf("%d%lf%lf",&b[i].o,&b[i].d.x,&b[i].d.y),much[i]=much[i-1]+(!b[i].o);
	fill(ans+1,ans+n+1,true);
	solve(1,n);
	for (int i=1;i<=n;++i) if (b[i].o) puts(much[i] && ans[i]?"Yes":"No");
	return 0;
}
原文地址:https://www.cnblogs.com/owenyu/p/7273817.html