【BZOJ4140】 共点圆加强版

这是一篇关于平面直角坐标系中处理共点圆问题的博客, Wayne需要进行n次操作,包括添加以(x, y)为圆心且过原点的圆,或者询问点(x, y)是否在所有已加入的圆内部。题目保证所有圆心在x轴上方,横坐标非零。输入包括n个操作描述,输出是对每个询问操作的“是”或“否”回答。样例输入和输出展示了具体的操作和判断结果。博主提到,由于题目要求在线处理,因此采用了二进制分组的方法,但发现此方法并不熟悉,通过学习模板才找到解决思路。" 132842388,19974244,Rockchip PWM背光配置与驱动详解,"['单片机', 'PWM', 'GPIO', '驱动开发', '嵌入式Linux']

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

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

第1行一个整数n。
接下来n行,每行第一个数是0或1,分别表示两种操作。
接着有两个实数x和y,具体意义见题面。注意询问进行了加密,x和y需要加上之前回答Yes的数量得到真正的询问。
Output

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

5

0 2.000000 3.000000

0 4.000000 1.000000

1 1.000000 1.000000

0 -4.000000 1.000000

1 0.000000 0.000000
Sample Output

Yes

No
HINT

Source

鸣谢talw001上传

改题的人绝对是个大毒瘤!好好地cdq加什么强制在线!
只好上二进制分组了
结果发现自己之前没写过二进制分组并不怎么会写…只好看了一发Claris模板然后幡然醒悟
为什么学的Claris模板然而时间就是比人家多2s

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define MAXN 500010
using namespace std;
int n,opt,top,num;
int l[32],r1[32],r2[32];
bool t;
double A,B,C,sum;
double sqr(double x)    {return x*x;}
struct Point
{
    double x,y;
}ins[MAXN],newq[MAXN],q1[MAXN],q2[MAXN];
inline bool cmp1(Point a,Point b)   {return a.x==b.x?a.y>b.y:a.x<b.x;}
inline bool cmp2(Point a,Point b)   {return a.x==b.x?a.y<b.y:a.x<b.x;}
inline void rebuild()//重建分组  
{
    while (num&&top-l[num]==l[num]-l[num-1])    num--;l[++num]=top;
    int L=l[num-1]+1,R=L-1,cnt=0;
    for (int i=L;i<=top;i++)    newq[++cnt]=ins[i];sort(newq+1,newq+cnt+1,cmp1);
    for (int i=1;i<=cnt;i++)
    {
        while (R>L&&(q1[R].y-q1[R-1].y)*(newq[i].x-q1[R].x)<=(newq[i].y-q1[R].y)*(q1[R].x-q1[R-1].x))   R--;
        q1[++R]=newq[i];
    }
    r1[num]=R;R=L-1;sort(newq+1,newq+cnt+1,cmp2);
    for (int i=1;i<=cnt;i++)
    {
        while (R>L&&(q2[R].y-q2[R-1].y)*(newq[i].x-q2[R].x)>=(newq[i].y-q2[R].y)*(q2[R].x-q2[R-1].x))   R--;
        q2[++R]=newq[i];
    }
    r2[num]=R;
}
inline double calc(Point x) {return A*x.x+B*x.y;}
inline bool query1(int l,int r)
{
    int mid1,mid2,len;double s1,s2;
    while (l<=r)
    {
        len=(r-l)/3;mid1=l+len;mid2=r-len;s1=calc(q1[mid1]);s2=calc(q1[mid2]);
        if (s1<s2)  {if (s1<C)  return t=1;r=mid2-1;}
        else    {if (s2<C)  return t=1;l=mid1+1;}
    }
    return 0;
}
inline bool query2(int l,int r)
{
    int mid1,mid2,len;double s1,s2;
    while (l<=r)
    {
        len=(r-l)/3;mid1=l+len;mid2=r-len;s1=calc(q2[mid1]);s2=calc(q2[mid2]);
        if (s1<s2)  {if (s1<C)  return t=1;r=mid2-1;}
        else    {if (s2<C)  return t=1;l=mid1+1;}
    }
    return 0;
}
inline void Query()
{
    t=0;
    for (int i=1;i<=num;i++)
    {
        if (B<0)    query1(l[i-1]+1,r1[i]); else    query2(l[i-1]+1,r2[i]);
        if (t)  return;
    }
}
int main()
{
    scanf("%d",&n);
    while (n--)
    {
        scanf("%d%lf%lf",&opt,&A,&B);A+=sum,B+=sum;
        if  (opt==0)    ins[++top].x=A,ins[top].y=B,rebuild();
        else    
        {
            if (!top)   {puts("No");continue;}
            C=sqr(A)+sqr(B);A*=2;B*=2;Query();puts(t?"No":"Yes");
            if (!t) sum++;
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值