CH Round #46A 磁力块
还是一道好题的
对于一个磁石是否被吸引,有两个关键字:距离和质量。(二维偏序??)
好像是很厉害的分块姿势,先按第一关键字排序,在块中按第二关键字排
进行bfs,对于当前磁石,有1~k-1个块是第一关键字全部小于等于当前磁石的,那么暴力从块首往后,找到第一个第二关键字大于当前磁石属性的,那么前面都捡走,以后可以从这里开始找。
暴力枚举第k个块找答案。
一个优化就是找k的时候直接比较当前块的最大值就行了,因为当前的属性肯定是>kmin,<kmax滴
(垃圾CH本机AC提交WA幸好最后我搞对了)
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; typedef long long LL; int n; struct node{LL dis,m,p,r;}a[310000];bool v[310000]; bool cmp1(node n1,node n2){return n1.m<n2.m;} bool cmp2(node n1,node n2){return n1.dis<n2.dis;} int block,st[310000]; struct LIST { LL p,r; }list[310000]; int be[610];LL mx[610]; int findk(LL p) { for(int i=1;i<=block;i++) if(p<mx[i])return i; return block+1; } int main() { freopen("1.in","r",stdin); freopen("1.out","w",stdout); LL xx,yy,x,y; scanf("%lld%lld%lld%lld%d",&xx,&yy,&list[1].p,&list[1].r,&n); for(int i=1;i<=n;i++) { scanf("%lld%lld%lld%lld%lld",&x,&y,&a[i].m,&a[i].p,&a[i].r); a[i].dis=(x-xx)*(x-xx)+(y-yy)*(y-yy); } sort(a+1,a+n+1,cmp1); block=(int(sqrt(double(n+1))))+1; for(int i=1;i<=n;i++)st[i]=(i-1)/block+1; for(int i=1;i<=block;i++) { int St=(i-1)*block+1,Ed=min(i*block,n);mx[i]=a[Ed].m; if(St<=Ed)sort(a+St,a+Ed+1,cmp2); } for(int i=1;i<=block;i++)be[i]=1; memset(v,false,sizeof(v)); int head=1,tail=2,ans=0; while(head<tail) { LL p=list[head].p,r=list[head].r; int k=findk(p); for(int i=1;i<=k-1;i++) { for(int j=be[i];j<=block&&(i-1)*block+j<=n;j++) { int u=(i-1)*block+j; if(a[u].dis>r*r){be[i]=j;break;} { if(v[u]==false) { v[u]=true; ans++; list[tail].p=a[u].p, list[tail].r=a[u].r; tail++; } } } } if(k!=block+1) { for(int j=be[k];j<=block&&(k-1)*block+j<=n;j++) { int u=(k-1)*block+j; if(a[u].dis>r*r)break; else if(a[u].m<=p) { if(v[u]==false) { v[u]=true; ans++; list[tail].p=a[u].p, list[tail].r=a[u].r; tail++; } } } } head++; } printf("%d\n",ans); return 0; }
pain and happy in the cruel world.