LOJ#2586. 「APIO2018」選圓圈 KDtree+剪枝

暴力枚舉的話是 $O(n^2)$ 的,但是我們可以維護每個圓的外接矩陣,然後顯然如果一個圓會被當前圓刪,外接矩陣一定有交集,所以就可以用 KDtree 來剪枝了.

直接做的話洛谷上能過,LOJ 上要在開始的時候把所有點都旋轉一個特定的角度來保證隨機性. 

code: 

#include <bits/stdc++.h>    
#define N 300007 
#define ll long long 
#define inf 1000000000 
#define eps 5e-2
#define setIO(s) freopen(s".in","r",stdin)
using namespace std;  
int d,n,ans[N];        
double sqr(double x) { return x*x; }  
struct data 
{
    int ch[2],si,id; 
    double p[2],mi[2],ma[2],cmi[2],cma[2],r;     
    bool operator<(const data b) const 
    {
        return p[d]==b.p[d]?p[d^1]<b.p[d^1]:p[d]<b.p[d];  
    } 
    int out(data b) 
    {
        int flag=0;   
        for(int i=0;i<2;++i)        
            if(mi[i]>b.ma[i]||ma[i]<b.mi[i]) flag=1; 
        return flag;                
    }
    int check(data b) 
    {   
        double dis1=sqr(p[0]-b.p[0])+sqr(p[1]-b.p[1]);      
        double dis2=sqr(r+b.r);    
        return dis2-dis1>=-eps;   
    }
}s[N];     
void pushup(int x,int y) 
{
    for(int i=0;i<2;++i) 
    {    
        s[x].mi[i]=min(s[x].mi[i],s[y].mi[i]);
        s[x].ma[i]=max(s[x].ma[i],s[y].ma[i]);  
    } 
} 
int build(int l,int r,int o) 
{   
    int mid=(l+r)>>1;  
    d=o,nth_element(s+l,s+mid,s+1+r),s[mid].si=1; 
    if(mid>l)   
    {
        s[mid].ch[0]=build(l,mid-1,o^1);  
        pushup(mid,s[mid].ch[0]),s[mid].si+=s[s[mid].ch[0]].si; 
    }
    if(r>mid) 
    {
        s[mid].ch[1]=build(mid+1,r,o^1);   
        pushup(mid,s[mid].ch[1]),s[mid].si+=s[s[mid].ch[1]].si;  
    }   
    return mid;  
} 
struct cir  
{
    double x,y,r; 
    int id;
    cir(double x=0,double y=0,int id=0,double r=0):x(x),y(y),id(id),r(r){}   
    bool operator<(const cir b) const { return r==b.r?id<b.id:r>b.r; }
}c[N];        
int query(int x,data b,int fa) 
{
    if(!s[x].si||s[x].out(b)) return 0;  
    int tp=0;         
    if(!ans[s[x].id]&&s[x].check(b))    
    {
        ans[s[x].id]=fa,tp=1; 
        s[x].mi[0]=s[x].mi[1]=s[x].cmi[0]=s[x].cmi[1]=inf;  
        s[x].ma[0]=s[x].ma[1]=s[x].cma[0]=s[x].cma[1]=-inf;       
    }                     
    for(int i=0;i<2;++i) 
        s[x].mi[i]=s[x].cmi[i],s[x].ma[i]=s[x].cma[i];    
    if(s[x].ch[0]) tp+=query(s[x].ch[0],b,fa),pushup(x,s[x].ch[0]);   
    if(s[x].ch[1]) tp+=query(s[x].ch[1],b,fa),pushup(x,s[x].ch[1]);  
    s[x].si-=tp;         
    return tp;          
}
const double sina=sqrt(2)/2;   
const double cosa=sqrt(2)/2;  
int main() 
{ 
    // setIO("input");     
    scanf("%d",&n);   
    for(int i=1;i<=n;++i) 
    {
        double a,b,r,x,y; 
        scanf("%lf%lf%lf",&a,&b,&r);      
        x=a*cosa-b*sina;   
        y=a*sina+b*cosa; 
        s[i].cmi[0]=s[i].mi[0]=x-r; 
        s[i].cma[0]=s[i].ma[0]=x+r;   
        s[i].cmi[1]=s[i].mi[1]=y-r; 
        s[i].cma[1]=s[i].ma[1]=y+r;
        s[i].p[0]=x,s[i].p[1]=y,s[i].id=i,s[i].r=r;         
        c[i]=cir(x,y,i,r);      
    }
    sort(c+1,c+1+n);  
    data tmp;  
    int root=build(1,n,0);            
    for(int i=1;i<=n;++i) 
    {  
        if(!ans[c[i].id]) 
        {                      
            tmp.p[0]=c[i].x,tmp.p[1]=c[i].y,tmp.r=c[i].r;  
            tmp.mi[0]=c[i].x-c[i].r,tmp.ma[0]=c[i].x+c[i].r;   
            tmp.mi[1]=c[i].y-c[i].r,tmp.ma[1]=c[i].y+c[i].r; 
            query(root,tmp,c[i].id);   
        }
    }
    for(int i=1;i<=n;++i)  printf("%d ",ans[i]);    
    return 0;  
}

  

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章