[关闭]
@ysner 2018-08-21T12:46:15.000000Z 字数 2618 阅读 1719

[APIO2018]Circle selection

kd-tree


题面

在平面上,有个圆,记为。我们尝试对这些圆运行这个算法:

被删除时,若循环中第步选择的圆是,我们说删除。对于每个圆,求出它是被哪一个圆删除的。

解析

题目太火,正解无从想象,准备暴力骗分。

什么东西能够快速维护平面上的东西?
二维树状数组、二维线段树?蒟蒻不会。。。
于是就只剩了。

本质上就是一个经过优化的暴力(优化在缩小搜索范围,只对近邻进行搜索),是靠剪枝吃饭的。
我们可以用它维护每个圆在轴的范围,即
这样相当于维护一个矩形,但是并不会漏掉答案,并且维护起来很方便。
于是建完树后,从前往后对每个圆通过暴力统计答案即可。

然而这样只有,我们需要更多剪枝。
可以注意到,如果搜到一个圆,在当前统计答案的圆的(矩形)范围之外,这个圆显然不会对答案有贡献,可以跳过。

于是就可以通过洛谷数据了?然而上跑不过最后一档。
把每个点转一个角度就可以

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstdlib>
  4. #include<cstring>
  5. #include<cmath>
  6. #include<algorithm>
  7. #include<vector>
  8. #define re register
  9. #define il inline
  10. #define ll long long
  11. #define db double
  12. #define ls t[k].l
  13. #define rs t[k].r
  14. #define eps 1e-6
  15. #define pf(x) ((db)(1.0)*(x)*(x))
  16. #define max(a,b) (((a)>(b)?(a):(b)))
  17. #define min(a,b) (((a)<(b)?(a):(b)))
  18. #define fp(i,a,b) for(re int i=a;i<=b;i++)
  19. #define fq(i,a,b) for(re int i=a;i>=b;i--)
  20. using namespace std;
  21. const int N=3e5+100;
  22. int now,n,rt,ans[N];
  23. struct dat
  24. {
  25. int d[2],r,id;
  26. bool operator < (const dat &o) const {return d[now]<o.d[now];}
  27. }a[N];
  28. struct node
  29. {
  30. dat a;
  31. int l,r,mn[2],mx[2];
  32. }t[N];
  33. il int gi()
  34. {
  35. re int x=0,t=1;
  36. re char ch=getchar();
  37. while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
  38. if(ch=='-') t=-1,ch=getchar();
  39. while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
  40. return x*t;
  41. }
  42. il void cmax(re int &x,re int y){x=max(x,y);}
  43. il void cmin(re int &x,re int y){x=min(x,y);}
  44. il bool cmp(dat x,dat y){return (x.r==y.r)?(x.id<y.id):(x.r>y.r);}
  45. struct kd_tree
  46. {
  47. il void upd(re int k,re int p)
  48. {
  49. cmin(t[k].mn[0],t[p].mn[0]);cmax(t[k].mx[0],t[p].mx[0]);
  50. cmin(t[k].mn[1],t[p].mn[1]);cmax(t[k].mx[1],t[p].mx[1]);
  51. }
  52. il void pushup(re int k)
  53. {
  54. re int x=t[k].a.d[0],y=t[k].a.d[1],r=t[k].a.r;
  55. t[k].mn[0]=x-r;t[k].mx[0]=x+r;
  56. t[k].mn[1]=y-r;t[k].mx[1]=y+r;
  57. if(ls) upd(k,ls);if(rs) upd(k,rs);
  58. }
  59. il void Build(re int &k,re int l,re int r,re int tag)
  60. {
  61. re int mid=l+r>>1;now=tag;
  62. nth_element(a+l,a+mid,a+r+1);k=mid;
  63. t[k].a=a[mid];
  64. if(l<mid) Build(ls,l,mid-1,tag^1);else ls=0;
  65. if(mid<r) Build(rs,mid+1,r,tag^1);else rs=0;
  66. pushup(k);
  67. }
  68. il int check(re int k,re dat A)
  69. {
  70. re int x=A.d[0],y=A.d[1],r=A.r+t[k].a.r,xx=t[k].a.d[0],yy=t[k].a.d[1];
  71. return pf(1ll*x-xx)+pf(1ll*y-yy)-eps<=pf(r);
  72. }
  73. il int far(re int k,re dat A)
  74. {
  75. re int x=A.d[0],y=A.d[1],r=A.r;
  76. if(x+r<t[k].mn[0]) return 1;
  77. if(y+r<t[k].mn[1]) return 1;
  78. if(x-r>t[k].mx[0]) return 1;
  79. if(y-r>t[k].mx[1]) return 1;
  80. return 0;
  81. }
  82. il void Query(re int k,re dat A)
  83. {
  84. if(far(k,A)) return;
  85. if(!ans[t[k].a.id]&&check(k,A)) ans[t[k].a.id]=A.id;
  86. if(ls) Query(ls,A);if(rs) Query(rs,A);
  87. }
  88. }kd;
  89. int main()
  90. {
  91. n=gi();
  92. fp(i,1,n)
  93. {
  94. a[i].d[0]=gi();a[i].d[1]=gi();a[i].r=gi();a[i].id=i;
  95. }
  96. kd.Build(rt,1,n,0);
  97. sort(a+1,a+1+n,cmp);
  98. fp(i,1,n) if(!ans[a[i].id]) kd.Query(rt,a[i]);
  99. fp(i,1,n) printf("%d ",ans[i]);puts("");
  100. return 0;
  101. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注