Description
WYF为了保证他自己能够吃到足够多的牛排,来补充自己的脑力,所以他建了两个补给站,坐标分别为 (ax,ay),(bx,by) ( a x , a y ) , ( b x , b y ) 。他有n个休息地点,第i个休息地点的坐标是 (xi,yi) ( x i , y i ) 。每个补给站都有一个补给半径,当一个休息地点在以一个补给站为圆心,该补给站的补给半径为半径的圆中时(包括在圆周上),那个休息地点就会获得补给。现在有 m m 个询问,每个询问会给出第一个补给站的补给半径 r1 r 1 和第二个补给站的补给半径 r2 r 2 ,WYF想知道有多少个休息地点会得到补给。
Input
输入的第一行包含
2
2
个整数,
n
n
与
m
m
。
第二行包含
4
4
个整数,
ax,ay,bx,by
a
x
,
a
y
,
b
x
,
b
y
。
第
3
3
至
n+2
n
+
2
行包含
2
2
个整数
x,y
x
,
y
。
第
n+3
n
+
3
至
n+m+2
n
+
m
+
2
行包含两个整数
r1,r2
r
1
,
r
2
。
Output
输出的第 1 1 至 m m 行包含 1 1 个整数,表示其所对应的询问的答案。
Data Constraint
对于 30% 30 % 的数据: n≤5000,m≤5000 n ≤ 5000 , m ≤ 5000 .
对于
100%
100
%
的数据:
n≤2∗105,m≤105
n
≤
2
∗
10
5
,
m
≤
10
5
,
ax,ay,bx,by,x,y∈[−100000,100000],r1,r2∈[0,300000]
a
x
,
a
y
,
b
x
,
b
y
,
x
,
y
∈
[
−
100000
,
100000
]
,
r
1
,
r
2
∈
[
0
,
300000
]
。
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个休息点能受到补给。
Solution
我们设
A(r1)∈{xi|dis(xi,a)<=r1};B(r2)∈{xi|dis(xi,a)<=r2}
A
(
r
1
)
∈
{
x
i
|
d
i
s
(
x
i
,
a
)
<=
r
1
}
;
B
(
r
2
)
∈
{
x
i
|
d
i
s
(
x
i
,
a
)
<=
r
2
}
则
ANS=A+B−A∩B
A
N
S
=
A
+
B
−
A
∩
B
。其中A,B是可以直接求得,问题在于求
A∩B
A
∩
B
。
在此,我们可用线段树来查询。
①将
r1
r
1
由小到大排序,然后将
A
A
也从小到大排序。
②枚举
questions
q
u
e
s
t
i
o
n
s
,将A中符合条件的点依次加入线段树中,直到不能加为止。
而线段树要储存的就是在
0
0
~
r2
r
2
范围内
A
A
中点出现过的次数。
③查询线段树
0
0
~
r2
r
2
区间的和,即为重复的个数。
Code
const maxn=300005;
maxq=100005;
var n,m,lim,wei,i:longint;
x1,x2,y1,y2,x,y,bin:int64;
a,b:real;
dis:array[0..maxn,1..2] of longint;
q:array[0..maxq,0..2] of longint;
ans:array[1..maxq] of longint;
tr,f1,f2:array[0..2*maxn] of longint;
function max(x,y:longint):longint;
begin
if x>y then exit(x) else exit(y);
end;
procedure qsort1(x,y:longint);
var k,i,j:longint;
begin
i:=x;
j:=y;
k:=dis[(x+y) div 2,1];
repeat
while dis[i,1]<k do inc(i);
while dis[j,1]>k do dec(j);
if i<=j then begin
dis[0]:=dis[i];
dis[i]:=dis[j];
dis[j]:=dis[0];
inc(i);
dec(j);
end;
until i>j;
if i<y then qsort1(i,y);
if j>x then qsort1(x,j);
end;
procedure qsort2(x,y:longint);
var k,i,j:longint;
begin
i:=x;
j:=y;
k:=q[(x+y) div 2,1];
repeat
while q[i,1]<k do inc(i);
while q[j,1]>k do dec(j);
if i<=j then begin
q[0]:=q[i];
q[i]:=q[j];
q[j]:=q[0];
inc(i);
dec(j);
end;
until i>j;
if i<y then qsort2(i,y);
if j>x then qsort2(x,j);
end;
procedure jia(v,x,y,z:longint);
var k:longint;
begin
if x=y then begin
inc(tr[v]);
exit;
end;
k:=(x+y) div 2;
if z<=k then jia(v*2,x,k,z) else jia(v*2+1,k+1,y,z);
tr[v]:=tr[v*2]+tr[v*2+1];
end;
procedure find(v,x,y,l,r:longint);
var m:longint;
begin
if (x=l) and (y=r) then begin
inc(bin,tr[v]);
exit;
end;
m:=(x+y) shr 1;
if r<=m then find(v*2,x,m,l,r) else
if l>m then find(v*2+1,m+1,y,l,r) else begin
find(v*2,x,m,l,m);
find(v*2+1,m+1,y,m+1,r);
end;
end;
procedure make(x,y,z:longint);
begin
while (wei<n) and (dis[wei+1,1]<=y) do begin
inc(wei);
jia(1,0,lim,dis[wei,2]);
end;
bin:=0;
find(1,0,lim,0,z);
ans[x]:=f1[y]+f2[z]-bin;
end;
procedure init;
begin
readln(n,m);
readln(x1,y1,x2,y2);
for i:=1 to n do begin
readln(x,y);
a:=sqrt(sqr(x-x1)+sqr(y-y1));
b:=sqrt(sqr(x-x2)+sqr(y-y2));
if a>trunc(a) then dis[i,1]:=trunc(a)+1 else dis[i,1]:=trunc(a);
if b>trunc(b) then dis[i,2]:=trunc(b)+1 else dis[i,2]:=trunc(b);
lim:=max(lim,dis[i,2]);
inc(f1[dis[i,1]]);
inc(f2[dis[i,2]]);
end;
for i:=2 to maxn do begin
inc(f1[i],f1[i-1]);
inc(f2[i],f2[i-1]);
end;
for i:=1 to m do begin
readln(q[i,1],q[i,2]);
q[i,0]:=i;
end;
end;
begin
init;
qsort1(1,n);
qsort2(1,m);
wei:=0;
for i:=1 to m do make(q[i,0],q[i,1],q[i,2]);
for i:=1 to m do writeln(ans[i]);
end.