【BZOJ2961】【Codevs2003】共点圆

2961: 共点圆
Time Limit: 30 Sec Memory Limit: 256 MB
Submit: 333 Solved: 141
[Submit][Status][Discuss]
Description

  在平面直角坐标系中,Wayne需要你完成n次操作,操作只有两种:
  1.0 x y。表示在坐标系中加入一个以(x, y)为圆心且过原点的圆。
  2.1 x y。表示询问点(x, y)是否在所有已加入的圆的内部(含圆周),且至少在一个圆内部(含圆周)。
  为了减少你的工作量,题目保证圆心严格在x轴上方(纵坐标为正),且横坐标非零。
Input

  第1行一个整数n。
  接下来n行,每行第一个数是0或1,分别表示两种操作。
  接着有两个实数x和y,具体意义见题面。
Output

  对于每个询问操作,如果点在所有已加入的圆内(或圆周上),则输出“Yes”(不含引号);否则输出“No”(不含引号)。
Sample Input
5

0 2.0000 3.0000

0 4.0000 1.0000

1 1.000000 1.000000

0 -3.0000 2.0000

1 1.000000 1.000000

Sample Output
Yes

No
HINT

对于100%的数据,n≤500000,所有坐标绝对值不超过10000。

  输入数据保证圆心纵坐标为正,横坐标非零。

  圆心坐标保留4位小数,询问点坐标保留6位小数,请选手注意控制精度。

Source

中国国家队清华集训 2012-2013 第二天

麻麻我终于会写半平面交了QUQ本来想练cdq玩的顺便学会了半平面交
虽然我的代码跑的奇慢荣登BZOJ倒数rank5但是毕竟A了不是吗233
这么简单的东西也不打太多注释了会被鄙视的(/ω\)
就是普通的凸包啊。。。
把插入的圆变成凸包点当半平面看凸包是否全部点在半平面内
具体做法2013集训队论文XHR神犇讲的很清楚了0-0我也不多说什么了(/ω\)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define MAXN 500100
#define MAXDBL 1e20
#define eps 1e-9
using namespace std;
int n;
bool ans[MAXN];
int flag;
struct Query
{
    int t;
    int op;
    double x,y;
    double k;
    bool operator <(const Query& a)const{
        return x<a.x;
    }
}q[MAXN],newq[MAXN];
int num;
bool com(Query a,Query b)
{
    return a.t<b.t;
}
double slope(int a,int b)
{
    if (!b) return -MAXDBL;
    if (fabs(q[a].x-q[b].x)<eps) return MAXDBL;
    return (q[b].y-q[a].y)/(q[b].x-q[a].x);
}
double dis(int a,int b)
{
    return sqrt((q[a].x-q[b].x)*(q[a].x-q[b].x)+(q[a].y-q[b].y)*(q[a].y-q[b].y));
}
int stack1[MAXN],stack2[MAXN];//分别维护上凸线(stack1)和下凸线(stack2)
bool comp(Query a,Query b)
{
    return a.k<b.k;
}
void solve(int l,int r)
{
    int mid=(l+r)>>1,tp1=l,tp2=mid+1;
    if (l==r) return;
    for (int i=l;i<=r;i++)
        if (q[i].t<=mid) newq[tp1++]=q[i];
        else newq[tp2++]=q[i];
    memcpy(q+l,newq+l,sizeof(Query)*(r-l+1));
    solve(l,mid);
    int top1=0,top2=0,j=1;
    for (int i=l;i<=mid;i++)
    {
        if (q[i].op==1) continue;
        while (top1>1&&(slope(stack1[top1-1],stack1[top1])-slope(stack1[top1-1],i))<eps) stack1[top1--]=0;
        stack1[++top1]=i;
        while (top2>1&&(slope(stack2[top2-1],stack2[top2])-slope(stack2[top2-1],i))>eps) stack2[top2--]=0;
        stack2[++top2]=i;
    }
    for (int i=mid+1;i<=r;i++)
    {
        if (q[i].op==0) continue;
        if (q[i].y>eps)
        {
            while (j<top2&&slope(stack2[j],stack2[j+1])<q[i].k) stack2[j++]=0;
            if (j<=top2&&dis(stack2[j],0)<dis(stack2[j],i)) ans[q[i].t]=1;
        }
        else
        {
            while (top1>1&&slope(stack1[top1-1],stack1[top1])<q[i].k) stack1[top1--]=0;
            if(stack2[j]) printf("%lf %lf\n",q[stack2[j]].x,q[stack2[j]].y);
            if (top1>=1&&dis(stack2[j],0)<dis(stack2[j],i)) ans[q[i].t]=1;
        }
    }
    solve(mid+1,r);
    tp1=l;tp2=mid+1;
    for (int i=l;i<=r;i++)
        if (tp1<=mid&&q[tp1]<q[tp2]||tp2>r) newq[i]=q[tp1++];
        else newq[i]=q[tp2++];
    memcpy(q+l,newq+l,sizeof(Query)*(r-l+1));
}
int main()
{
    scanf("%d",&n);
    q[0].x=0;q[0].y=0;
    for (int i=1;i<=n;i++) ans[i]=0;
    for (int i=1;i<=n;i++)
    {
        scanf("%d%lf%lf",&q[i].op,&q[i].x,&q[i].y);
        if (fabs(q[i].y)<=eps) q[i].k=MAXDBL;
        else q[i].k=-q[i].x/q[i].y;
        q[i].t=i;
    }
    sort(q+1,q+n+1,comp);
    solve(1,n);
    sort(q+1,q+n+1,com);
    for (int i=1;i<=n;i++)
        if (q[i].op==1) 
        {
            if (!ans[q[i].t]&&flag) puts("Yes");
            else puts("No");
        }
        else if (!flag) flag=1;
}

你可能感兴趣的:(半平面交,cdq分治)