bzoj5465 [APIO 2018] 选圆圈 kd树

版权声明:转吧转吧这条东西只是来搞笑的。。 https://blog.csdn.net/jpwang8/article/details/88083411

Description


在平面上,有 n 个圆,记为 c_1, c_2, \ldots, c_n 。我们尝试对这些圆运行这个算法:

  1. 找到这些圆中半径最大的。如果有多个半径最大的圆,选择编号最小的。记为 c_i 。
  2. 删除 ci 及与其有交集的所有圆。两个圆有交集当且仅当平面上存在一个点,这个点同时在这两个圆的圆周上或圆内。
    (如果平面上存在一个点被这两个圆所包含,我们称这两个圆有交集。一个点被一个圆包含当且仅当它位于圆内或圆周上。)
  3. 重复上面两个步骤直到所有的圆都被删除。
    在这里插入图片描述
    当 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;
}

猜你喜欢

转载自blog.csdn.net/jpwang8/article/details/88083411