此题是2012年区域赛泰国一个赛区的题目,可能是东南亚赛区比较水,做完前面3道签到题之后,其实发现这个题也是一个大水题,只要能够稍微yy一下就可以了,毕竟东南亚,这个题也很考英语,具体意思为给你n个点的坐标,然后再给你两个圆的坐标圆心,并且给q个询问,每次给你两个圆的半径r1和r2,问你在这个图中没有被两个圆包住的点减去同时被2个圆包住的点的数量有多少???如果小于0,输出0。
这个题目做法其实不难,具体就是图的转化,可以想一下,未被包住的点的数量减去同时都被包住的点的数量等于图中所有的点n减去两个圆分别包含的点的数量(此时同时被包住的点的数量会算两遍),所以此题就简单多了,先求出所有点到圆的距离,再对距离进行排序,然后对每次给定的半径,直接二分寻找存在多少个点被包到圆里面,直接输出n减去两次求的的数量之和即可AC。。。PS:由于此题距离如果直接使用,可能会有一定的精度误差很难去处理,我就直接用距离平方去计算,从而避免了精度问题,具体代码如下:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
using namespace std;
const double eps=1e-6;
struct st
{
int x,y;
}p[200005];
int cal(st p,st c)
{
return (p.x-c.x)*(p.x-c.x)+(p.y-c.y)*(p.y-c.y);
}
int cd1[200005],cd2[200005];
int cmp(const void *a,const void *b)
{
return *(int*)a-*(int*)b;
}
int main()
{
// freopen("in.txt","r",stdin);
int n,ti=1;
while(cin>>n&&n!=0)
{
for(int i=0;i<n;i++)
scanf("%d%d",&p[i].x,&p[i].y);
st c1,c2;
int m;
scanf("%d%d%d%d%d",&c1.x,&c1.y,&c2.x,&c2.y,&m);
for(int i=0;i<n;i++)
{
cd1[i]=cal(p[i],c1);
cd2[i]=cal(p[i],c2);
}
qsort(cd1,n,sizeof(cd1[0]),cmp);
qsort(cd2,n,sizeof(cd2[0]),cmp);
printf("Case %d:\n",ti);
ti++;
for(int i=0;i<m;i++)
{
int r1,r2;
scanf("%d%d",&r1,&r2);
int ans1=upper_bound(cd1,cd1+n,r1*r1)-cd1,ans2=upper_bound(cd2,cd2+n,r2*r2)-cd2;
if(n-ans1-ans2<=0)
cout<<0<<endl;
else
cout<<n-(ans1+ans2)<<endl;
}
}
return 0;
}