acdream 1127 Base Station 树状数组

本文详细探讨了移动通信系统中,如何通过调整主基站的发射功率来评估不同覆盖半径下,子基站的激活状态及非激活状态的数量,通过实例分析了如何利用算法优化设备配置,提高网络效率。

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

Problem Description

 

移动通信系统中,通信网的建立主要通过基站来完成。

基站可以分为主基站和子基站。子基站和各个移动用户进行连接,子基站必须通过主基站来和外界实现通信。主基站可以覆盖到的范围是一个圆形区域,子基站和主基站的距离小于半径r才能被该主基站覆盖到。半径r由主基站的发射功率确定。

某个区域的移动通信网,包含2个主基站和N个子基站。它们的位置都可以对应到一个整数坐标上。如果子基站至少被一个主基站覆盖,则该子基站是激活的。

现在通信公司在调试设备,它们不停地改变主基站的发射功率,当两个主基站的覆盖半径分别为r1和r2时,需要知道有多少个子基站处于非激活状态。

 

 

 

Input

有若干组输入数据。

第一行是四个整数:x1、y1、x2、y2(1<=x1、y1、x2、y2<=10^9),表示两个主基站的坐标是(x1,y1)和(x2,y2)。

第二行是一个整数N(1<=N<=100000),表示有N个子基站。

接下来的N行,每行两个整数x、y(1<=x, y<=10^9),表示每个子基站的坐标。

接下来一行包含一个整数M(1<=M<=100000),表示有M个询问。

接下来的M行,每行两个整数r1、r2(1<=r1, r2<=10^9),表示询问当两个主基站的覆盖半径为r1和r2时,处于非激活状态的子基站数。
Output

对每个查询,输出答案。

Sample Input
1 10 5 2
5
2 6
1 9
3 8
6 7
4 12
5
1 1
3 2
8 2
2 2
3 2
Sample Output
5
3
0
4
3

  给你两个圆心和N个点。M个询问,每个询问告诉你两个圆的半径,问有多少个点在圆外,包括圆上。

  把所有点按照到第一个圆心的距离从远到近排序,把询问按照r1从大到小排序,再用一个数组b存下每个点到第二个圆圆心的距离,把这个数组b从小到大排序,每个点就根据他到第二个圆圆心的距离相对大小在数组中对应了一个下标。这样对于所有的询问只需遍历一遍所有的点,每次把到第一个圆圆心的距离大于等于r1的在b中的位置(位置用二分在b中查找)加入树状数组,加入完之后再用二分找到r2在b中对应的位置l,用sum[N]-sum[l-1]就是在r1外但是不在r2内的点的数目,也就是这个询问要求的答案。由于询问是按r1从大到小排的序,在当前圆外的点肯定在下个圆外,只用在当前位置接着往下找还有没有在下个圆外的点就行了,因此对于全部询问所有点只用遍历一遍。

  注意询问已经排序,存答案的时候要存在原来的位置中。

  复杂度O(M*lgN)

#include<iostream>
#include<queue>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<set>
#include<map>
#include<vector>
#include<stack>
#include<algorithm>
#define eps 1e-9
#define MAXN 100010
#define MAXM 110
#define MOD 999983
typedef long long LL;
using namespace std;
int M,N;
LL X1,Y1,X2,Y2,c[MAXN],b[MAXN],ans[MAXN];
struct Point{
    LL x,y;
    bool operator < (const Point& a) const{
        return x>a.x;
    }
}p[MAXN];
struct Query{
    LL r1,r2,id;
    bool operator < (const Query& a) const{
        return r1>a.r1;
    }
}q[MAXN];
LL lowbit(LL x){
    return x&(-x);
}
void add(LL i,LL v){
    while(i<=N){
        c[i]+=v;
        i+=lowbit(i);
    }
}
LL sum(LL i){
    LL ret=0;
    while(i>0){
        ret+=c[i];
        i-=lowbit(i);
    }
    return ret;
}
int main(){
    freopen("in.txt","r",stdin);
    while(scanf("%lld%lld%lld%lld",&X1,&Y1,&X2,&Y2)!=EOF){
        scanf("%d",&N);
        LL xt,yt,r1,r2;
        memset(c,0,sizeof(c));
        for(int i=0;i<N;i++){
            scanf("%lld%lld",&xt,&yt);
            p[i].x=(xt-X1)*(xt-X1)+(yt-Y1)*(yt-Y1);
            p[i].y=(xt-X2)*(xt-X2)+(yt-Y2)*(yt-Y2);
            b[i+1]=p[i].y;
        }
        sort(p,p+N);
        sort(b+1,b+1+N);
        scanf("%d",&M);
        for(int i=0;i<M;i++){
            scanf("%lld%lld",&r1,&r2);
            q[i].r1=r1*r1;
            q[i].r2=r2*r2;
            q[i].id=i;
        }
        sort(q,q+M);
        LL index=0;
        for(int i=0;i<M;i++){
            while(index<N&&p[index].x>=q[i].r1){
                LL loc=lower_bound(b+1,b+N+1,p[index].y)-b;
                add(loc,1);
                index++;
            }
            LL L=lower_bound(b+1,b+N+1,q[i].r2)-b;
            ans[q[i].id]=sum(N)-sum(L-1);
        }
        for(int i=0;i<N;i++) printf("%lld\n",ans[i]);
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值