洛谷4631 & UOJ415 & LOJ2586:[APIO2018] Circle selection 选圆圈——题解

https://www.luogu.com.cn/problem/P4631

http://uoj.ac/problem/415

https://loj.ac/problem/2586

正解貌似是可持久化扫描线……不会告辞。

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 选圆圈——题解

上一篇:Windows应急响应和系统加固(9)——Windows Apache日志提取和安全分析


下一篇:DATASNAP ISAPI中间件