BZOJ-3276 磁力块
磁力
分块
整个过程像 bfs,就把能吸引的加入队列,然后一个个判断能不能吸引,暴力的复杂度是 \(O(n^2)\)
可以通过分块的技术,先按照质量分块,在块内再对距离进行分块,每次搜索的时候一定存在一个 k,使得 \([1,k-1]\) 的块内,所有的点的质量都符合条件,同时 \([k+1,t]\) 的块内所有点的质量都大于吸引力,而对于第 k 个块,就只能暴力判断
在一个块中,因为我们是对距离排序,所以直接从左到右找,如果找成功了,就把块的左边界缩减一下
对于第 k 个块,只能暴力跑,我这里是用一个 \(vis\) 来标记是否吸引过
bzoj 的数据比 acwing 上边的数据弱
acwing 的题得提前预处理距离,就不用每次算,能减少一点常数,因为都是和所在位置进行距离判断,所以直接预处理就好
时间复杂度是 \(O(n \sqrt{n})\)
感觉我这种分块写法虽然容易写,但是常数确实大,空间消耗也大
#include <iostream>
#include <cmath>
#include <cstdio>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long ll;
const int maxn = 250000 + 10;
const double eps = 1e-8;
int R[maxn], L[maxn], pos[maxn], vis[maxn];
double hm[maxn];
struct node
{
double x, y, p, m, r, dis;
node(){}
node(double _x, double _y, double _p, double _m, double _r){x = _x; y = _y; r = _r; p = _p; m = _m;}
}num[maxn];
vector<node>q;
bool cmp_m(const node& a, const node& b)
{
return a.m < b.m;
}
double dis(const node& a, const node& b)
{
double xx = a.x - b.x;
double yy = a.y - b.y;
return sqrt(xx * xx + yy * yy);
}
bool cmp_dis(const node& a, const node& b)
{
return a.dis < b.dis;
}
int dcmp(double x)
{
return (x > eps) - (x < -eps);
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
double x, y, p, r, m;
int n;
cin >> x >> y >> p >> r >> n;
q.push_back(node(x, y, p, 100, r));
for(int i=1; i<=n; i++)
{
cin >> x >> y >> m >> p >> r;
num[i] = node(x, y, p, m, r);
num[i].dis = dis(num[i], q[0]);
}
sort(num + 1, num + n + 1, cmp_m);
int t = sqrt(n);
for(int i=1; i<=t; i++)
{
L[i] = R[i-1] + 1;
R[i] = i * t;
}
if(R[t] < n)
{
t++;
L[t] = R[t-1] + 1;
R[t] = n;
}
for(int i=1; i<=t; i++)
{
for(int j=L[i]; j<=R[i]; j++)
pos[j] = i;
hm[i] = num[R[i]].m;
sort(num + L[i], num + R[i] + 1, cmp_dis);
}
for(int i=0; i<q.size(); i++)
{
int tp = 1;
while(tp < t && dcmp(q[i].p - hm[tp]) == 1) tp++;
for(int j=1; j<tp; j++)
{
for(int k=L[j]; k<=R[j]; k++)
{
if(vis[k]) {L[j]++; continue;}
if(dcmp(q[i].p - num[k].m) >= 0 && dcmp(q[i].r - num[k].dis) >= 0)
{
q.push_back(num[k]);
L[j]++;
}
else break;
}
}
for(int j=L[tp]; j<=R[tp]; j++)
{
if(vis[j]) continue;
if(dcmp(q[i].p - num[j].m) >= 0 && dcmp(q[i].r - num[j].dis) >= 0)
{
vis[j] = 1;
q.push_back(num[j]);
}
}
}
cout << q.size() - 1 << endl;
return 0;
}