BZOJ5465 : [APIO 2018] 选圆圈

假设最大的圆半径为$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;
}

  

posted @ 2019-01-31 00:02  Claris  阅读(1163)  评论(2编辑  收藏  举报