https://www.luogu.com.cn/problem/P4631
正解貌似是可持久化扫描线……不会告辞。
KD-TREE把圆存下来,每个点存最大覆盖所有圆的矩形。
然后按照题意从大到小枚举圆去找它的交,我们把圆视作矩形看看是否和当前查询节点的矩形有交,没有就告辞,有就往下找就好了。
复杂度玄学,通过旋转坐标系可以过。
(算了了当年心愿吧)
#include<cmath> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; typedef long double dl; const int K=2; const int N=3e5+5; const dl eps=1e-7; const dl alpha=0.233; inline int read(){ int X=0,w=0;char ch=0; while(!isdigit(ch)){w|=ch==‘-‘;ch=getchar();} while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar(); return w?-X:X; } int D,cnt,tot,num,root,rubbish[N]; struct Point{ dl x,y; Point(dl x0=0,dl y0=0){x=x0,y=y0;} }; Point Rotate(Point a,dl rad){//逆时针旋转rad return Point(a.x*cos(rad)-a.y*sin(rad),a.x*sin(rad)+a.y*cos(rad)); } inline int epssgn(dl x){ if(fabs(x)<eps)return 0; return x<0?-1:1; } struct Circle{ dl d[K],r;int id; Circle(){} Circle(Point p,dl r_,int id_){ d[0]=p.x;d[1]=p.y;r=r_;id=id_; } bool operator <(const Circle &a)const{ return epssgn(d[D]-a.d[D])<0; } }a[N]; struct KDTREE{ int s[2]; dl x[2],y[2]; Circle p; }tr[N]; #define ls tr[o].s[0] #define rs tr[o].s[1] #define cmax(a,b) (a<b?a=b:a) #define cmin(a,b) (a>b?a=b:a) inline int newnode(){ if(!tot)return ++cnt; return rubbish[tot--]; } inline void upd(int f,int x){ cmin(tr[f].x[0],tr[x].x[0]),cmax(tr[f].x[1],tr[x].x[1]); cmin(tr[f].y[0],tr[x].y[0]),cmax(tr[f].y[1],tr[x].y[1]); } inline void pushup(int o){ tr[o].x[0]=tr[o].p.d[0]-tr[o].p.r; tr[o].x[1]=tr[o].p.d[0]+tr[o].p.r; tr[o].y[0]=tr[o].p.d[1]-tr[o].p.r; tr[o].y[1]=tr[o].p.d[1]+tr[o].p.r; if(ls)upd(o,ls);if(rs)upd(o,rs); } int build(int l,int r,int d){ D=d;int mid=(l+r)>>1; nth_element(a+l,a+mid,a+r+1); int o=newnode(); tr[o].p=a[mid]; if(l<mid)ls=build(l,mid-1,d^1),upd(o,ls);else ls=0; if(mid<r)rs=build(mid+1,r,d^1),upd(o,rs);else rs=0; pushup(o);return o; } inline dl dis(Circle a,Circle b){ dl x=a.d[0]-b.d[0],y=a.d[1]-b.d[1]; return x*x+y*y; } inline bool check(Circle a,Circle b){ dl R=a.r+b.r; return epssgn(dis(a,b)-R*R)<=0; } inline bool outside(int o,Circle x){ if(epssgn(x.d[0]-x.r-tr[o].x[1])>0)return 1; if(epssgn(x.d[0]+x.r-tr[o].x[0])<0)return 1; if(epssgn(x.d[1]-x.r-tr[o].y[1])>0)return 1; if(epssgn(x.d[1]+x.r-tr[o].y[0])<0)return 1; return 0; } int ans[N]; void query(int o,Circle x){ if(!o)return; if(outside(o,x))return; if(!ans[tr[o].p.id]&&check(x,tr[o].p))ans[tr[o].p.id]=x.id; query(ls,x);query(rs,x); } bool cmp(Circle a,Circle b){ return epssgn(a.r-b.r)>0||(epssgn(a.r-b.r)==0&&a.id<b.id); } int main(){ int n=read(); for(int i=1;i<=n;i++){ dl x=read(),y=read(),r=read(); a[i]=Circle(Rotate(Point(x,y),alpha),r,i); } root=build(1,n,0); sort(a+1,a+n+1,cmp); for(int i=1;i<=n;i++)if(!ans[a[i].id])query(root,a[i]); for(int i=1;i<=n;i++)printf("%d ",ans[i]); puts(""); return 0; }
+++++++++++++++++++++++++++++++++++++++++++
+本文作者:luyouqi233。 +
+欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+
+++++++++++++++++++++++++++++++++++++++++++
洛谷4631 & UOJ415 & LOJ2586:[APIO2018] Circle selection 选圆圈——题解