本题仔细分析发现也是一个二维偏序问题,并且因为强制在线,所以不能用莫队来做,因此考虑分块的做法
这道题,因为题目第一个要求是距离小于半径,因此我们直接算出距离后,通过对距离排序,之后分块
这样的分块就会产生一个性质,在某些块中的所有半径都小于r,而在边界块中,则使用暴力。
在块中我们按质量排序
之后我们只需要给每个块分配一个指针,用于判断质量和吸力的关系,这个指针会一直往后推,不用回溯。
这题还可以替换磁力块,其实就相当于bfs,将已经吸入的都可以当作x,y这个点,只要最后队列空了,说明就结束了
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=2e5+10; const int mod=1e9+7; struct node{ ll dis,m; ll r,p; }s[2*N+10],d[510][510]; ll sign[5050]; int e[5050]; int st[5050][5050]; int cnt[5050]; int n,block; ll x,y,x2,y2; bool cmpa(node a,node b){ return a.dis<b.dis; } bool cmpb(node a,node b){ return a.m<b.m; } void init(){ int i; for(i=1;i<=n;i++){ cin>>x2>>y2>>s[i].m>>s[i].p>>s[i].r; s[i].dis=(x2-x)*(x2-x)+(y2-y)*(y2-y); s[i].r*=s[i].r; } block=sqrt(n); sort(s+1,s+1+n,cmpa); for(i=1;i<=n;i++){ d[(i-1)/block+1][(i-1)%block]=s[i]; sign[(i-1)/block+1]=s[i].dis; } for(i=1;i<=(n-1)/block+1;i++){ if(i*block<=n) e[i]=block; else e[i]=n%block; sort(d[i],d[i]+e[i],cmpb); } } bool check(ll a,ll b){ return a<=b; } void bfs(){ queue<node> q; q.push(s[0]); st[0][0]=1; while(q.size()){ node t=q.front(); q.pop(); int i; for(i=1;i<=(n-1)/block+1;i++){ if(sign[i]<=t.r){ while(cnt[i]<e[i]&&check(d[i][cnt[i]].m,t.p)){ if(!st[i][cnt[i]]){ st[i][cnt[i]]=1; q.push(d[i][cnt[i]]); } cnt[i]++; } } else{ for(int j=0;j<e[i];j++){ if(d[i][j].dis<=t.r&&d[i][j].m<=t.p){ if(!st[i][j]){ q.push(d[i][j]); st[i][j]=1; } } } break; } } } } int main(){ ios::sync_with_stdio(0); cin>>x>>y>>s[0].p>>s[0].r>>n; s[0].r*=s[0].r; init(); bfs(); int i; ll ans=0; for(i=1;i<=(n-1)/block+1;i++){ for(int j=0;j<e[i];j++){ if(st[i][j]) ans++; } } cout<<ans<<endl; return 0; }View Code