补给站

本文介绍了一种解决补给站覆盖问题的算法,通过线段树优化查询过程,实现高效计算在不同补给半径下受补给的休息地点数量。

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

Description

  WYF为了保证他自己能够吃到足够多的牛排,来补充自己的脑力,所以他建了两个补给站,坐标分别为(ax,ay),(bx,by)(ax,ay),(bx,by)。他有n个休息地点,第i个休息地点的坐标是(xi,yi)(xi,yi)。每个补给站都有一个补给半径,当一个休息地点在以一个补给站为圆心,该补给站的补给半径为半径的圆中时(包括在圆周上),那个休息地点就会获得补给。现在有 m  m 个询问,每个询问会给出第一个补给站的补给半径 r1  r1 和第二个补给站的补给半径 r2  r2 ,WYF想知道有多少个休息地点会得到补给。

Input

  输入的第一行包含 2  2 个整数, n  n  m m
  第二行包含 4  4 个整数,ax,ay,bx,byax,ay,bx,by
  第 3  3  n+2  n+2 行包含 2  2 个整数 x,y x,y
  第 n+3  n+3  n+m+2  n+m+2 行包含两个整数 r1,r2 r1,r2

Output

  输出的第 1  1  m  m 行包含 1  1 个整数,表示其所对应的询问的答案。

Data Constraint

  对于30%30%的数据:n5000,m5000n≤5000,m≤5000.

  对于100%100%的数据:n2105,m105n≤2∗105,m≤105,
  
  ax,ay,bx,by,x,y[100000,100000],r1,r2[0,300000]ax,ay,bx,by,x,y∈[−100000,100000],r1,r2∈[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|disxia<=r1}B(r2){xi|disxia<=r2}A(r1)∈{xi|dis(xi,a)<=r1};B(r2)∈{xi|dis(xi,a)<=r2}
  则 ANS=A+BAB ANS=A+B−A∩B。其中A,B是可以直接求得,问题在于求ABA∩B
  在此,我们可用线段树来查询。


  ①将 r1  r1 由小到大排序,然后将 A  A 也从小到大排序。
  ②枚举questionsquestions,将A中符合条件的点依次加入线段树中,直到不能加为止。
  而线段树要储存的就是在 0  0 ~ r2r2范围内 A  A 中点出现过的次数。
  ③查询线段树 0  0 ~ r2 r2区间的和,即为重复的个数。

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.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值