zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    oauth2-server-php for windows 的那些坑 (研究中...)
    你使用 Web 平台安装程序命令行工具
    Window 下安装 Redis
    windows下安装redis 以及phpredis的扩展 (windows redis php&php7)
    windows下redis的安装配置和php扩展使用phpredis
    常用网络端口
    PHP OAuth 2.0 Server
    Database Setup
    php各版本下载
    纯 html 以及 js 多域名跳转
  • 原文地址:https://www.cnblogs.com/owenyu/p/7273817.html
Copyright © 2011-2022 走看看