BZOJ5465 APIO2018選圓圈(KD-Tree+堆)
阿新 • • 發佈:2018-12-23
考慮亂搞,用矩形框圓放KD-Tree上,如果當前刪除的圓和矩形有交就遞迴下去刪。為防止被卡,將座標系旋轉一定角度即可。注意eps稍微設大一點,最好開上long double。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> #include<queue> #include<vector> using namespace std;#define ll long long #define N 300010 #define double long double char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while(c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } const double PI=acos(-1.0); const double eps=1E-6; int n,c,cnt,root,ans[N]; struct circle { double d[2];int r,i; bool operator <(constcircle&a) const { return d[c]<a.d[c]; } void rotate(double alpha) { double u=d[0]*cos(alpha)-d[1]*sin(alpha); double v=d[0]*sin(alpha)+d[1]*cos(alpha); d[0]=u,d[1]=v; } }a[N]; struct KDTree{int ch[2];double a[2][2];circle p; }tree[N]; double sqr(double x){return x*x;} bool iscross(circle x,circle y){return sqr(x.d[0]-y.d[0])+sqr(x.d[1]-y.d[1])<sqr(x.r+y.r)+eps;} double max(double x,double y,double z){return max(max(x,y),z);} double iscross(circle p,double a[2][2]){return sqr(max(p.d[0]-a[0][1],a[0][0]-p.d[0],(double)0))+sqr(max(p.d[1]-a[1][1],a[1][0]-p.d[1],(double)0))<sqr(p.r)+eps;} void build(int &k,int l,int r,int op) { if (l>r) return; k=++cnt,c=op;int mid=l+r>>1;nth_element(a+l,a+mid,a+r+1); tree[k].p=a[mid]; tree[k].a[0][0]=a[mid].d[0]-a[mid].r,tree[k].a[0][1]=a[mid].d[0]+a[mid].r, tree[k].a[1][0]=a[mid].d[1]-a[mid].r,tree[k].a[1][1]=a[mid].d[1]+a[mid].r; for (int i=l;i<=r;i++) tree[k].a[0][0]=min(tree[k].a[0][0],a[i].d[0]-a[i].r),tree[k].a[0][1]=max(tree[k].a[0][1],a[i].d[0]+a[i].r), tree[k].a[1][0]=min(tree[k].a[1][0],a[i].d[1]-a[i].r),tree[k].a[1][1]=max(tree[k].a[1][1],a[i].d[1]+a[i].r); build(tree[k].ch[0],l,mid-1,op^1); build(tree[k].ch[1],mid+1,r,op^1); } void find(int k,circle x) { if (!ans[tree[k].p.i]&&iscross(tree[k].p,x)) ans[tree[k].p.i]=x.i; if (tree[k].ch[0]&&iscross(x,tree[tree[k].ch[0]].a)) find(tree[k].ch[0],x); if (tree[k].ch[1]&&iscross(x,tree[tree[k].ch[1]].a)) find(tree[k].ch[1],x); } struct cmp { bool operator ()(const circle&a,const circle&b) const { return a.r<b.r||a.r==b.r&&a.i>b.i; } }; priority_queue<circle,vector<circle>,cmp> q; int main() { #ifndef ONLINE_JUDGE freopen("bzoj5465.in","r",stdin); freopen("bzoj5465.out","w",stdout); const char LL[]="%I64d\n"; #else const char LL[]="%lld\n"; #endif n=read(); for (int i=1;i<=n;i++) { a[i].d[0]=read(),a[i].d[1]=read(),a[i].i=i,a[i].r=read(); a[i].rotate(PI/6); q.push(a[i]); } build(root,1,n,0); while (1) { while (!q.empty()&&ans[q.top().i]) q.pop(); if (q.empty()) break; circle x=q.top();q.pop();ans[x.i]=x.i; find(root,x); } for (int i=1;i<=n;i++) printf("%d ",ans[i]); return 0; }