https://www.acwing.com/problem/content/252/

https://ac.nowcoder.com/acm/contest/1034/B

题目

在一片广袤无垠的原野上,散落着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) 处吸引更多的磁石。

小取酒想知道,他最多能获得多少块磁石呢?

$1\leqslant N\leqslant 250000$

$−10^9\leqslant x,y\leqslant10^9$

$1\leqslant m,p,r\leqslant10^9$

题解

这是个需要二维查询的题目,首先可以BFS。因为是分块例题= =

分块方法为:先将整个区间按照质量排序,分为D块,再把D块内按照距离排序

第一维用O(D)的时间找到所有质量都小于等于吸力的块,第二维每一块都顺序遍历确定距离比半径小的,并且保证每一个只遍历一次(因为距离已经排好了)

剩下的块直接遍历。

每个元素只遍历一次,但是在bfs的每一步,每个块都要遍历一次,还要考虑剩下的块,所以时间复杂度是$\mathcal{O}(n\times (1+n/D+D))$,为了不升阶,可以取$D=\sqrt{n}$

AC代码

#include<bits/stdc++.h>
using namespace std;
#define REP(i,a,b) for(register int i=(a); i<(b); i++)
#define REPE(i,a,b) for(register int i=(a); i<=(b); i++)
#define PERE(i,a,b) for(register int i=(a); i>=(b); i--)
#ifdef sahdsg
#define DBG(...) printf(__VA_ARGS__)
#else
#define DBG(...) void(0)
#endif
typedef long long ll;
#define MAXN 250007

struct node{
	int m,p;
	ll dis, r;
};
bool cmp1(const node&l, const node&r) {
	return l.m<r.m;
}
bool cmp2(const node&l, const node&r) {
	return l.dis<r.dis;
}
int D,L;
node arr[MAXN]; int M[MAXN];
int pos[MAXN],ed[MAXN];
#define x0 fadfjklwa
#define y0 jfdalskas
int x0,y0,pl,n;
ll rl;
int ans;
queue<int> q;
bool vis[MAXN];
void go() {
	ans=0;
	q.push(-1);
	REP(i,0,n) {
		vis[i]=0;
	}
	while(!q.empty()) {
		int now=q.front(); q.pop();
		if(~now) {
			pl = arr[now].p;
			rl = arr[now].r;
		}
		int i=0;
		for(;i<D &&M[i]<=pl;i++) {
			for(;pos[i]<ed[i] && arr[pos[i]].dis<=rl; pos[i]++) if(!vis[pos[i]]){
				vis[pos[i]]=1;
				ans++;
				q.push(pos[i]);
			}
		}
		if(i<D) {
			REP(j,pos[i],ed[i]) if(!vis[j]) {
				if(arr[j].dis<=rl && arr[j].m<=pl) {
					vis[j]=1;
					ans++;
					q.push(j);
				}
			}
		}
	}

}
int main() {
	scanf("%d%d%d%lld%d", &x0, &y0, &pl, &rl, &n);rl*=rl;
	REP(i,0,n) {
		ll x,y;
		int m,p,r;
		scanf("%lld%lld%d%d%d", &x, &y, &m, &p, &r);
		x-=x0, y-=y0;
		arr[i]=(node){m,p,x*x+y*y,(ll)r*r};
	}
	sort(arr,arr+n,cmp1);
	L=sqrt((double)n); if(L==0) L=1;
	D=n/L; pos[0]=0;
	REP(i,0,D) {
		ed[i]=pos[i+1]=pos[i]+L;
		M[i]=arr[ed[i]-1].m;
		sort(arr+pos[i], arr+ed[i],cmp2);
	}
	if(pos[D]<n) {
		ed[D]=n;
		M[D]= arr[n-1].m;
		sort(arr+pos[D], arr+ed[D],cmp2);

		pos[++D]=n;
	}
	go();
	printf("%d\n", ans);
}
02-01 01:26