链接: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)(x_0,y_0)(x0,y0)处,我们可以视磁石L的坐标为(x0,y0)(x_0,y_0)(x0,y0)。
小取酒手持磁石L并保持原地不动,所有可以被L吸引的磁石将会被吸引过来。
在每个时刻,他可以选择更换任意一块自己已经获得的磁石(当然也可以是自己最初携带的L磁石)在(x0,y0)(x_0,y_0)(x0,y0)处吸引更多的磁石。
小取酒想知道,他最多能获得多少块磁石呢?

输入描述:

第一行五个整数x0,y0,pL,rL,Nx_0,y_0,p_L,r_L,Nx0,y0,pL,rL,N,表示小取酒所在的位置,磁石L磁力、吸引半径和原野上散落磁石的个数。
接下来N行每行五个整数x,y,m,p,r,描述一块磁石的性质。

输出描述:

输出一个整数,表示最多可以获得的散落磁石个数(不包含最初携带的磁石L)。
示例1

输入

0 0 5 10 5
5 4 7 11 5
-7 1 4 7 8
0 2 13 5 6
2 -3 9 3 4
13 5 1 9 9

输出

3

备注:

1≤N≤250000,1\leq N\leq 250000,1N250000,
−109≤x,y≤109,−10^9\leq x,y\leq 10^9,109x,y109,
1≤m,p,r≤1091\leq m,p,r\leq 10^91m,p,r109

1)暴力遍历时间复杂度大概在O(n^2),也就是说数据规模超过5000就会TLE,那么很明显这个方法不行
2)考虑排序,按照与(x0,y0)的距离从小到大排序,这个时候算法的时间虽有减少,但是依旧会TLE
3)2中超限大概原因就是要遍历每个d之内的所有数据,因为存在质量与吸引力之间的关系,所以要考虑每个磁石的质量,就会耽误时间
4)既然3中分析出来是因为质量的原因那么我们可以对质量也进行处理,直接1-n排序没有什么意义,联想到用分块排序,在块内对数据进行质量排序
5)排好序后利用,bfs框架对所有能队头磁铁被吸引的磁铁进行入队操作,知道队列为空
6)分块的好处是在前k-1个块内直接只需要比较质量移动块的L[i]即可

完成数据分块的代码值得注意:
1 int cnt = 0, len = sqrt(n);
2 for (int i = 1; i <= n; i += len) {
3     lef[++cnt] = i;
4     rig[cnt] = min(n, i + len - 1);
5     maxdis[cnt] = mag[rig[cnt]].d;
6     sort(mag + lef[cnt], mag + 1 + rig[cnt], cmp_m);
7 }

但是wrong了很多次,因为,ll p = mag[s].p;,本该将p定义为long long ,粗心写成了int

AC代码如下:
 1 #include <cmath>
 2 #include <queue>
 3 #include <cstdio>
 4 #include <algorithm>
 5 #define ll long long 
 6 using namespace std;
 7 
 8 const int N = 250005;
 9 struct node {
10     ll d, m, p, r;
11 }mag[N];
12 ll  maxdis[510];
13 int lef[510], rig[510], vis[N];
14 
15 bool cmp_d(node a, node b) {
16     return a.d < b.d;
17 }
18 bool cmp_m(node a, node b) {
19     return a.m < b.m;
20 }
21 
22 int main(void)
23 {
24     int n;
25     ll sx, sy;
26     scanf("%lld%lld%lld%lld%d", &sx, &sy, &mag[0].p, &mag[0].r, &n);
27     mag[0].r *= mag[0].r;
28 
29     ll x, y;
30     for (int i = 1; i <= n; i++) {
31         scanf("%lld%lld%lld%lld%lld", &x, &y, &mag[i].m, &mag[i].p, &mag[i].r);
32         mag[i].d = (x - sx) * (x - sx) + (y - sy) * (y - sy);
33         mag[i].r *= mag[i].r;
34     }
35 
36     sort(mag + 1, mag + 1 + n, cmp_d);
37 
38     int cnt = 0, len = sqrt(n);
39     for (int i = 1; i <= n; i += len) {
40         lef[++cnt] = i;
41         rig[cnt] = min(n, i + len - 1);
42         maxdis[cnt] = mag[rig[cnt]].d;
43         sort(mag + lef[cnt], mag + 1 + rig[cnt], cmp_m);
44     }
45 
46     int ans = -1;
47     queue<int>q;
48     q.push(0);
49     vis[0] = 1;
50     while (!q.empty()) {
51         int s = q.front();
52         q.pop();
53         ++ans;
54         ll u = mag[s].r;//引力半径
55         ll p = mag[s].p;//引力
56 
57         for (int i = 1; i <= cnt; i++) {
58             if (maxdis[i] <= u) {
59                 for (int& j = lef[i]; j <= rig[i] && mag[j].m <= p; j++) {
60                     if (!vis[j]){
61                         q.push(j);
62                         vis[j] = 1;
63                     }
64                 }
65             }
66             else {
67                 for (int j = lef[i]; j <= rig[i]; j++) {
68                     if (!vis[j] && mag[j].m <= p && mag[j].d <= u) {
69                         vis[j] = 1;
70                         q.push(j);
71                     }
72                 }
73                 break;
74             }
75         }
76     }
77     printf("%d\n", ans);
78 
79     return 0;
80 }