Description
WYF为了保证他自己能够吃到足够多的牛排,来补充自己的脑力,所以他建了两个补给站,坐标分别为(ax,ay),(bx,by)。他有n个休息地点,第i个休息地点的坐标是(xi,yi)。每个补给站都有一个补给半径,当一个休息地点在以一个补给站为圆心,该补给站的补给半径为半径的圆中时(包括在圆周上),那个休息地点就会获得补给。现在有m个询问,每个询问会给出第一个补给站的补给半径r1和第二个补给站的补给半径r2,WYF想知道有多少个休息地点会得到补给。
Input
输入的第一行包含2个整数,n与m。
第二行包含4个整数,ax,ay,bx,by。
第3至n+2行包含2个整数x,y。
第n+3至n+m+2行包含两个整数r1,r2。
Output
输出的第1至m行包含1个整数,表示其所对应的询问的答案。
Sample Input
4 2
-1 0 2 0
0 0
1 1
2 2
0 2
3 1
1 1
Sample Output
3
1
【样例说明】
对于第一个询问,第1,2,4个休息点都能受到补给。
对于第二个询问,只有第1个休息点能受到补给。
其实这种类似于覆盖的问题还是挺好做的,因为数据并没有要求我们强制在线,所以我们可以考虑一下用离线处理。
如果把题目简化成只有一个补给站,那么处理起来就简单了,先把每个休息点离补给站的距离排个序,然后对于每一个询问进行二分查找就很容易做出来了。
但题目是有两个补给站,所以就有可能出现都被两个补给站覆盖的重复的休息点,所以只要领用刚刚的思想,且找出重复的点,把他减掉就行了。
这时候询问可以离线的特点就可以排上用场了。先假设将点按照与第 1 个补给站距离排序后存入的数组为 a,按照与第 2 个补给站距离排序后存入数组 b。将所有询问按照第 1 个补给站的半径从小到大排序。如果按顺序遍历这些询问的话,对于每个询问 我们可以动态得知a 数组中,有前 xi 个点被第 1 个补给站覆盖。显然 xi−1≤xi,即当前询问比上一个询问可能多覆盖了 xi−xi−1 个点。这时候如果给这些新覆盖的点打上标记,同时查询 b 数组中距离在指定范围内、且没有被标记的点的个数,不就避免了重复计数的情况吗?
对于有特征的区间查询,我们可以考虑用树状数组或线段树解决,最后用二分查找答案就行了,实现时要注意一下细节。个人建议用树状数组,因为这毕竟打得短吗。呵呵。。
时间复杂度大概是O(n logn+m logm) 注意要开longlong,因为求距离是会爆掉int
以下在树状数组实现下的代码
#include <cstdio>
#include <cmath>
#include <iostream>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for (int i=a;i<=b;i++)
#define N 200005
#define M 100005
using namespace std;
struct Re
{
long long x,y,z;
}b[N],Q[M];
struct Samjia
{
long long x,y;
}a[N];
long long n,m,ax,ay,bx,by;
long long now=0,t=1;
long long ans[M],c[N],d[N],e[N],tree[N];
bool cmp(Samjia a,Samjia b)
{
return (a.x<b.x);
}
bool cmp2(Re a,Re b)
{
return (a.x<b.x || (a.x==b.x && a.y<b.y));
}
int Lowbit(int x)
{
return (x&(x^(x-1)));
}
int GetSum(int p)
{
long long ans=0;
while (p)
{
ans+=tree[p];
p-=Lowbit(p);
}
return ans;
}
void Change(int p)
{
while (p<=n)
{
tree[p]++;
p+=Lowbit(p);
}
}
void Find(int l,int r,int i)
{
while (l<r)
{
int mid=(l+r)/2+1;
if (e[mid]<=Q[i].y) l=mid;
else r=mid-1;
}
ans[Q[i].z]=now+d[l]-GetSum(d[l]);
}
int main()
{
scanf("%lld%lld",&n,&m);
scanf("%lld%lld%lld%lld",&ax,&ay,&bx,&by);
fo(i,1,n)
{
long long xx,yy;
scanf("%lld%lld",&xx,&yy);
a[i].x=1LL*(xx-ax)*(xx-ax)+1LL*(yy-ay)*(yy-ay);
a[i].y=1LL*(xx-bx)*(xx-bx)+1LL*(yy-by)*(yy-by);
}
sort(a+1,a+1+n,cmp);
fo(i,1,n)
{
b[i].x=a[i].y;
b[i].y=a[i].x;
b[i].z=i;
}
sort(b+1,b+1+n,cmp2);
long long wz=0;
b[0].x=e[0]=-1;
long long tot=0;
fo(i,1,n)
{
c[b[i].z]=i;
if (b[i].x>b[wz].x)
{
d[tot]=i-1;
e[++tot]=b[i].x;
wz=i;
}
}
d[tot]=n;
fo(i,1,m)
{
scanf("%lld%lld",&Q[i].x,&Q[i].y);
Q[i].x=Q[i].x*Q[i].x;
Q[i].y=Q[i].y*Q[i].y;
Q[i].z=i;
}
sort(Q+1,Q+1+m,cmp2);
fo(i,1,m)
{
while (t<=n && a[t].x<=Q[i].x)
{
now++;
Change(c[t]);
t++;
}
Find(0,tot,i);
}
fo(i,1,m) printf("%lld\n",ans[i]);
return 0;
}