描述
在一片广袤无垠的原野上,散落着N块磁石。每个磁石的性质可以用一个五元组(x,y,m,p,r)描述,其中x,y表示其坐标,m是磁石的质量,p是磁力,r是吸引半径。若磁石A与磁石B的距离不大于磁石A的吸引半径,并且磁石B的质量不大于磁石A的磁力,那么A可以吸引B。
小取酒带着一块自己的磁石L来到了这篇原野的(x0,y0)处,我们可以视为磁石L的坐标为(x0,y0)。小取酒手持磁石L并保持原地不动,所有可以被L吸引的磁石将会被吸引过来。在每个时刻,他可以选择更换任意一块自己已经获得的磁石(当然也可以是自己最初携带的L磁石)在(x0,y0)处吸引更多的磁石。小取酒想知道,他最多能获得多少块磁石呢?
输入格式第一行五个整数x0,y0,pL,rL,N,表示小取酒所在的位置,磁石L磁力、吸引半径和原野上散落磁石的个数。
接下来N行每行五个整数x,y,m,p,r,描述一块磁石的性质。 输出格式输出一个整数,表示最多可以获得的散落磁石个数(不包含最初携带的磁石L)。
把所有石头按照质量排序分成sqrt(n)块,每一块里面再按照距离排序。
用一块石头的时候,先找到所有质量全小于当前磁力的整块,然后按顺序拿走距离满足要求的,多出来的那一块暴力。
整个操作可以分成两部分,取整块的和取不完整的。对于整块的,寻找需要O(sqrt(n))次,总共寻找O(n)次。每块只会被取一次,总共O(n)次。多出来的一段,每次暴力O(sqrt(n))个,暴力O(n)次。所以总的复杂度O(n*sqrt(n))。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define LL long long
using namespace std;
const double eps=1e-6;
struct rock
{int m,p,r;double d;
}a[250010];
int rd()
{int x=0,f=1;char c=getchar();while ((c<'0'||c>'9')&&c!='-') c=getchar();if (c=='-'){f=-1;c=getchar();}while (c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}return x*f;
}
bool cmpm(const rock &r1,const rock &r2)
{return r1.m<r2.m;
}
bool cmpd(const rock &r1,const rock &r2)
{return r1.d<r2.d;
}
bool out[250010];
int L[510],R[510],maxm[510],to[510],n,tot,que[250010];
int main()
{int i,j,k,m,n,p,q,x0,y0,hd,tl,ans=0;double x,y,z;x0=rd();y0=rd();a[0].p=rd();a[0].r=rd();n=rd();for (i=1;i<=n;i++){p=rd();q=rd();a[i].m=rd();a[i].p=rd();a[i].r=rd();a[i].d=sqrt((LL)(p-x0)*(p-x0)+(LL)(q-y0)*(q-y0)+0.0);}sort(a+1,a+n+1,cmpm);tot=sqrt(n+0.1);for (i=1;i<=tot;i++){L[i]=R[i-1]+1;to[i]=L[i]-1;R[i]= i==tot?n:L[i]+tot-1;maxm[i]=a[R[i]].m;}for (i=1;i<=tot;i++)sort(a+L[i],a+R[i]+1,cmpd);hd=tl=1;while (hd<=tl){p=que[hd++];for (i=1;i<=tot&&maxm[i]<=a[p].p;i++){while (to[i]<R[i]&&a[to[i]+1].d<=eps+a[p].r){to[i]++;if (!out[to[i]]){que[++tl]=to[i];ans++;out[to[i]]=1;}}}if (i<=tot)for (j=to[i]+1;j<=R[i];j++)if (out[j]==0&&a[j].d<=eps+a[p].r&&a[j].m<=a[p].p){out[j]=1;ans++;que[++tl]=j;}}printf("%d\n",ans);
}