版权声明:转吧转吧这条东西只是来搞笑的。。 https://blog.csdn.net/jpwang8/article/details/88083411
Description
在平面上,有 n 个圆,记为 c_1, c_2, \ldots, c_n 。我们尝试对这些圆运行这个算法:
- 找到这些圆中半径最大的。如果有多个半径最大的圆,选择编号最小的。记为 c_i 。
- 删除 ci 及与其有交集的所有圆。两个圆有交集当且仅当平面上存在一个点,这个点同时在这两个圆的圆周上或圆内。
(如果平面上存在一个点被这两个圆所包含,我们称这两个圆有交集。一个点被一个圆包含当且仅当它位于圆内或圆周上。) - 重复上面两个步骤直到所有的圆都被删除。
当 ci 被删除时,若循环中第1步选择的圆是 cj ,我们说 ci 被 cj 删除。对于每个圆,求出它是被哪一个圆删除的。
-1e9<=xi,yi<=1e9, 1<=ri<=1e9
1<=n<=3e5
Solution
我是一只咸鱼~~写这题只是为了写kd树
去年考场上按subtask打了线段树+枚举的又臭又长的暴力,也只有19分,真的菜
我们用矩形框住一个圆,然后对矩形建kd树。查询交的时候判掉相离的矩形然后暴力走就可以了
为了不被卡,可以考虑把坐标系旋转若干角度,比如我这里转了20°。实际操作因为是ioi赛制因此可以调参(雾
似乎没啥好说的啊
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <math.h>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define sqr(x) ((x)*(x))
const int N=600005;
const double eps=1e-3;
const double pi=acos(-1);
const double cosa=cos(pi/9.0);
const double sina=sin(pi/9.0);
int wjp;
struct Cir {double x,y,r; int id;} c[N];
struct treeNode {
int son[2],id;
double mx[2],mn[2],p[2],r;
bool operator <(const treeNode &b) const {
return p[wjp]<b.p[wjp];
}
void init(int idd) {
id=idd;
mx[0]=mn[0]=p[0]=c[idd].x;
mx[1]=mn[1]=p[1]=c[idd].y;
r=c[idd].r;
}
} t[N],Q;
int ans[N];
int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
void Max(double &x,double v) {
(x<v)?(x=v):0;
}
void Min(double &x,double v) {
(x>v)?(x=v):0;
}
int push_up(int x) {
t[x].mx[0]=t[x].mn[0]=t[x].p[0];
t[x].mx[1]=t[x].mn[1]=t[x].p[1];
int ls=t[x].son[0],rs=t[x].son[1];
if (ls) {
Max(t[x].mx[0],t[ls].mx[0]); Max(t[x].mx[1],t[ls].mx[1]);
Min(t[x].mn[0],t[ls].mn[0]); Min(t[x].mn[1],t[ls].mn[1]);
}
if (rs) {
Max(t[x].mx[0],t[rs].mx[0]); Max(t[x].mx[1],t[rs].mx[1]);
Min(t[x].mn[0],t[rs].mn[0]); Min(t[x].mn[1],t[rs].mn[1]);
}
return x;
}
int build(int l,int r,int R) {
int mid=(l+r)>>1;
wjp=R; std:: nth_element(t+l,t+mid,t+r+1);
if (l<mid) t[mid].son[0]=build(l,mid-1,!R);
if (mid<r) t[mid].son[1]=build(mid+1,r,!R);
return push_up(mid);
}
bool check(int x) {
if (Q.p[0]+Q.r+Q.r+eps<t[x].mn[0]) return 1;
if (Q.p[1]+Q.r+Q.r+eps<t[x].mn[1]) return 1;
if (Q.p[0]-Q.r-Q.r>t[x].mx[0]+eps) return 1;
if (Q.p[1]-Q.r-Q.r>t[x].mx[1]+eps) return 1;
return 0;
}
bool in(int x) {
return sqr(Q.p[0]-t[x].p[0])+sqr(Q.p[1]-t[x].p[1])-eps<=sqr(t[x].r+Q.r);
}
void query(int x,int now) {
if (!x||check(x)) return ;
if (!ans[t[x].id]&&in(x)) ans[t[x].id]=now;
query(t[x].son[0],now);
query(t[x].son[1],now);
}
bool cmp(Cir a,Cir b) {
return (a.r==b.r)?(a.id<b.id):(a.r>b.r);
}
int main(void) {
freopen("data.in","r",stdin);
int n=read();
rep(i,1,n) {
double x=read(),y=read();
c[i].x=x*cosa-y*sina;
c[i].y=x*sina+y*cosa;
// c[i].x=x,c[i].y=y;
c[i].r=read(),c[i].id=i;
t[i].init(i);
}
int rt=build(1,n,0);
std:: sort(c+1,c+n+1,cmp);
rep(i,1,n) if (!ans[c[i].id]) {
ans[c[i].id]=c[i].id;
Q.p[0]=c[i].x;
Q.p[1]=c[i].y;
Q.r=c[i].r;
query(rt,c[i].id);
}
rep(i,1,n) printf("%d ", ans[i]);
return 0;
}