【loj2586】【APIO2018】选圆圈

题目

\(n\) 个圆$c_1,c_2, \cdots , c_n $,执行如下的操作:

找到剩下的半径最大的圆删除并删除所有和它有交的其他并没有被删除的圆;

求每个圆是被那个圆删除的;

$1 \le n \le 3 \times 10^5 $ ;

描述

  • kdt做法:
    记录每个圆围成的举行作为剪枝,直接模拟删除;

    记得旋转一下,然后eps开1e-3就好;

  • 搬运一下$n \ log^2n $做法(orz yww):

    考虑找到和\(c_i\) 相交的半径最大的被自己删除的圆 ;

    这样的圆一定满足互相不相交;

    由于半径比 \(c_i\) 大,所以如果相交一定会和 \(c_i\) 平行坐标轴的四条切线有交;

    所以用扫描线+cdq分治即可;

    //懒得写正解了这是暴力:
    #include<bits/stdc++.h>
    #define eps 1e-3
    #define ld double
    using namespace std;
    const int N=300010;
    const ld sq2=sqrt(2);
    int n,WD,pos[N],bl[N],ls[N],rs[N],tr[N],rt;///
    struct P{ld x,y;};///
    ld mn[N][2],mx[N][2];///
    struct C{P o;ld r,mn[2],mx[2];int id;}c[N];///
    int dcmp(ld x){return fabs(x)<eps?0:x<0?-1:1;}///
    bool cmp(C A,C B){return !dcmp(A.r-B.r)?A.id<B.id:A.r>B.r;}///
    bool cmpD(int A,int B){return !WD?c[A].o.x<c[B].o.x:c[A].o.y<c[B].o.y;}///
    ld len(P A,P B){return (A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y);}///
    bool judge(C A,C B){return dcmp(len(A.o,B.o)-(A.r+B.r)*(A.r+B.r))<=0;}///
    void rotate(P&A){A=(P){(A.x-A.y)/sq2,(A.x+A.y)/sq2};}///
    char gc(){
    	static char*p1,*p2,s[1000000];
    	if(p1==p2)p2=(p1=s)+fread(s,1,1000000,stdin);
    	return(p1==p2)?EOF:*p1++;
    }///
    int rd(){
    	int x=0,f=1;char C=gc();
    	while(C<'0'||C>'9'){if(C=='-')f=-1;C=gc();}
    	while(C>='0'&&C<='9'){x=x*10+C-'0';C=gc();}
    	return x*f;
    }///
    void build(int&k,int l,int r,int d){
    	WD=d;k=(l+r)>>1;
    	nth_element(tr+l,tr+k,tr+r+1,cmpD);
    	mn[k][0]=c[tr[k]].mn[0];
    	mx[k][0]=c[tr[k]].mx[0];
    	mn[k][1]=c[tr[k]].mn[1];
    	mx[k][1]=c[tr[k]].mx[1];
    	if(l<k){
    		build(ls[k],l,k-1,d^1);
    		for(int i=0;i<2;++i){
    			mn[k][i]=min(mn[k][i],mn[ls[k]][i]);
    			mx[k][i]=max(mx[k][i],mx[ls[k]][i]);
    		}
    	}
    	if(k<r){
    		build(rs[k],k+1,r,d^1);
    		for(int i=0;i<2;++i){
    			mn[k][i]=min(mn[k][i],mn[rs[k]][i]);
    			mx[k][i]=max(mx[k][i],mx[rs[k]][i]);
    		}
    	}
    }///
    bool jud(int x,int y){return !x||mx[x][0]<c[y].mn[0]-eps||mn[x][0]>c[y].mx[0]+eps||mx[x][1]<c[y].mn[1]-eps||mn[x][1]>c[y].mx[1]+eps;}///
    void query(int k,int x){
    	if(!bl[tr[k]]&&judge(c[tr[k]],c[x]))bl[tr[k]]=c[x].id;
    	if(!jud(ls[k],x))query(ls[k],x);
    	if(!jud(rs[k],x))query(rs[k],x);
    }///
    int main(){
    //	freopen("B.in","r",stdin);
    //	freopen("B.out","w",stdout);
    	n=rd();
    	for(int i=1;i<=n;++i){
    		c[i].o.x=rd();c[i].o.y=rd();
    		rotate(c[i].o);c[i].r=rd();
    		c[i].mn[0]=c[i].o.x-c[i].r;
    		c[i].mx[0]=c[i].o.x+c[i].r;
    		c[i].mn[1]=c[i].o.y-c[i].r;
    		c[i].mx[1]=c[i].o.y+c[i].r;
    		c[i].id=tr[i]=i;
    	}///
    	sort(c+1,c+n+1,cmp);
    	for(int i=1;i<=n;++i)pos[c[i].id]=i;
    	build(rt,1,n,0);
    	for(int i=1;i<=n;++i){
    		if(!bl[i])query(rt,i);
    	}
    	for(int i=1;i<=n;++i)printf("%d ",bl[pos[i]]);
    	return 0;//
    }//
    
posted @ 2019-04-30 08:40  大米饼  阅读(290)  评论(0编辑  收藏  举报