【五校联考2day1】补给站题解
题目描述
WYF为了保证他自己能够吃到足够多的牛排,来补充自己的脑力,所以他建了两个补给站,坐标分别为(ax,ay),(bx,by)。他有n个休息地点,第i个休息地点的坐标是(xi,yi)。每个补给站都有一个补给半径,当一个休息地点在以一个补给站为圆心,该补给站的补给半径为半径的圆中时(包括在圆周上),那个休息地点就会获得补给。现在有m个询问,每个询问会给出第一个补给站的补给半径r1和第二个补给站的补给半径r2,WYF想知道有多少个休息地点会得到补给。
输入
输入的第一行包含2个整数,n与m。
第二行包含4个整数,ax,ay,bx,by。
第3至n+2行包含2个整数x,y。
第n+3至n+m+2行包含两个整数r1,r2。
输出
输出的第1至m行包含1个整数,表示其所对应的询问的答案。
样例输入 复制
4 2 -1 0 2 0 0 0 1 1 2 2 0 2 3 1 1 1
样例输出 复制
3 1 【样例说明】 对于第一个询问,第1,2,4个休息点都能受到补给。 对于第二个询问,只有第1个休息点能受到补给。
数据范围限制
对于30%的数据:n≤5000,m≤5000.
对于100%的数据:n≤2*10^5,m≤10^5,ax,ay,bx,by,x,y∈[-100000,100000],r1,r2∈[0,300000]。
思路
容斥原理,a|b=a+b-a&b,二分查找a,b,线段树维护a&b即可。
代码见下
#include<bits/stdc++.h>
using namespace std;
long long n,m,ax,ay,bx,by,lo=3e5,x[200005],y[200005],re1[200005],re2[200005],ef[300005],es[200005],r1,r2,l,r,md,mid,md2;
struct one{
long long a,b,c,d;
}re[200005],rr[200005];
bool cmp(one a1,one b1){
if(a1.a!=b1.a){
return a1.a<b1.a;
}
else{
return a1.b<b1.b;
}
}
bool cmp2(one a1,one b1){
return a1.c<b1.c;
}
long long abc(long long a1,long long b1,long long c1){
long long o1=sqrt((a1-ax)*(a1-ax)+(b1-ay)*(b1-ay)),o2=sqrt((a1-bx)*(a1-bx)+(b1-by)*(b1-by));
if(o1*o1<(a1-ax)*(a1-ax)+(b1-ay)*(b1-ay)){
o1++;
}
if(o2*o2<(a1-bx)*(a1-bx)+(b1-by)*(b1-by)){
o2++;
}
if(c1==1){
return o1;
}
else{
return o2;
}
}
long long te[4000006],lz[4000006],siz[4000006],xx;
void alz(int a1,long long v){
te[a1]+=siz[a1]*v;
lz[a1]+=v;
}//a1打标记值v
void dow(int a1){
alz(a1*2,lz[a1]);
alz(a1*2+1,lz[a1]);
lz[a1]=0;
}//a1下发标记至儿子
void bu(int a1,int l,int r){
siz[a1]=r-l+1;
if(l==r){
te[a1]=0;
return ;
}
int mid=(l+r)/2;
bu(a1*2,l,mid);
bu(a1*2+1,mid+1,r);
te[a1]=te[a1*2]+te[a1*2+1];
return ;
}//l~r建树节点a1
void ci(int a1,int l,int r,int x,int y,long long v){
if(l>=x&&r<=y){
alz(a1,v);
return ;
}
int mid=(l+r)/2;
dow(a1);
if(x<=mid){
ci(a1*2,l,mid,x,y,v);
}
if(mid+1<=y){
ci(a1*2+1,mid+1,r,x,y,v);
}
te[a1]=te[a1*2]+te[a1*2+1];
return ;
}//x~y区间加v至l~r区间a1点
long long co(int a1,int l,int r,int x,int y){
if(x<=l&&r<=y){
return te[a1];
}
int mid=(l+r)/2;
long long dbdb=0;
dow(a1);
if(mid>=x){
dbdb+=co(a1*2,l,mid,x,y);
}
if(mid+1<=y){
dbdb+=co(a1*2+1,mid+1,r,x,y);
}
return dbdb;
}//x~y区间问至l~r区间a1点
int main(){
// freopen("08080.in","r",stdin);
// freopen("12121.out","w",stdout);
cin>>n>>m;
cin>>ax>>ay>>bx>>by;
for(int i=1;i<=n;i++){
cin>>x[i]>>y[i];
re[i].a=abc(x[i],y[i],1);
re[i].b=abc(x[i],y[i],2);
re1[i]=abc(x[i],y[i],1);
re2[i]=abc(x[i],y[i],2);
}
sort(re+1,re+n+1,cmp);
sort(re1+1,re1+n+1);
sort(re2+1,re2+n+1);
for(int i=1;i<=m;i++){
cin>>rr[i].a>>rr[i].b;
rr[i].c=i;
}
sort(rr+1,rr+m+1,cmp);
bu(1,0,lo);
for(int i=1;i<=m;i++){
r1=rr[i].a;
r2=rr[i].b;
l=1;
r=n;
md=0;
while(l<=r){
mid=(l+r)/2;
if(re1[mid]<=r1){
md=max(md,mid);
l=mid+1;
}
else{
r=mid-1;
}
}
l=1;
r=n;
md2=0;
while(l<=r){
mid=(l+r)/2;
if(re2[mid]<=r2){
md2=max(md2,mid);
l=mid+1;
}
else{
r=mid-1;
}
}
es[i]=md;
for(int j=es[i-1]+1;j<=es[i];j++){
ci(1,0,lo,re[j].b,re[j].b,1);
}
rr[i].d=md+md2-co(1,0,lo,0,r2);
}
sort(rr+1,rr+m+1,cmp2);
for(int i=1;i<=m;i++){
cout<<rr[i].d<<endl;
}
return 0;
}

浙公网安备 33010602011771号