![BZOJ5465 : [APIO 2018] 选圆圈 BZOJ5465 : [APIO 2018] 选圆圈](https://image.shishitao.com:8440/aHR0cHM6Ly9ia3FzaW1nLmlrYWZhbi5jb20vdXBsb2FkL2NoYXRncHQtcy5wbmc%2FIQ%3D%3D.png?!?w=700&webp=1)
假设最大的圆半径为$R$,以$2R$为大小将地图划分为一个个格子,那么每个圆只需要检查圆心在附近$9$个格子内部的所有圆。
在当前圆的半径不足$\frac{R}{2}$时重构网格,那么最多重构$O(\log R)$次,且每个圆最多被检查常数次。
时间复杂度$O(n\log n\log R)$,利用Hash可以做到$O(n\log R)$。
#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
const int N=300010,inf=1000000000,BUF=13000000;
int n,m,i,x,y,q[N],ans[N],size;char Buf[BUF],*buf=Buf;
struct E{int x,y,r;E(){}E(int _x,int _y,int _r){x=_x,y=_y,r=_r;}}e[N],f[N];
vector<int>g[N],tmp;
inline void read(int&a){int f=0;for(a=0;*buf<45;buf++);if(*buf==45)f=1,buf++;while(*buf>47)a=a*10+*buf++-48;if(f)a=-a;}
inline bool cmp(int x,int y){
if(e[x].r!=e[y].r)return e[x].r>e[y].r;
return x<y;
}
inline bool cmpe(const E&a,const E&b){
if(a.x!=b.x)return a.x<b.x;
return a.y<b.y;
}
inline void init(int _){
if(size&&size/2<_)return;
size=_;
int i,j,k,cnt;
m=0;
for(i=1;i<=n;i++)if(!ans[i]){
int x=e[i].x/size,y=e[i].y/size;
f[++m]=E(x,y,i);
}
sort(f+1,f+m+1,cmpe);
cnt=0;
for(i=1;i<=m;i=j){
for(j=i;j<=m&&f[i].x==f[j].x&&f[i].y==f[j].y;j++);
f[++cnt]=f[i];
g[cnt].clear();
for(k=i;k<j;k++)g[cnt].push_back(f[k].r);
}
m=cnt;
}
inline int ask(int x,int y){
int l=1,r=m,mid;
while(l<=r){
mid=(l+r)>>1;
if(f[mid].x==x&&f[mid].y==y)return mid;
if(f[mid].x<x||f[mid].x==x&&f[mid].y<y)l=mid+1;else r=mid-1;
}
return 0;
}
inline bool check(int i,int j){return 1LL*(e[i].r+e[j].r)*(e[i].r+e[j].r)>=1LL*(e[i].x-e[j].x)*(e[i].x-e[j].x)+1LL*(e[i].y-e[j].y)*(e[i].y-e[j].y);}
inline void apply(int S){
if(ans[S])return;
init(e[S].r*2);
int x=e[S].x/size,y=e[S].y/size,i,j,k,o,t;
for(i=x-1;i<=x+1;i++)for(j=y-1;j<=y+1;j++)if(i>=0&&j>=0){
o=ask(i,j);
if(!o||!g[o].size())continue;
tmp.clear();
for(k=0;k<g[o].size();k++){
t=g[o][k];
if(check(S,t))ans[t]=S;else tmp.push_back(t);
}
swap(g[o],tmp);
}
}
int main(){
fread(Buf,1,BUF,stdin);read(n);
for(i=1;i<=n;i++){
read(x),read(y),read(e[i].r);
e[i].x=x+inf;
e[i].y=y+inf;
q[i]=i;
}
sort(q+1,q+n+1,cmp);
for(i=1;i<=n;i++)apply(q[i]);
for(i=1;i<=n;i++)printf("%d%c",ans[i],i<n?' ':'\n');
return 0;
}