【bzoj 3815】卡常数

找球面点,用k-d树,在不可能出现的长方体剪枝即可。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#define Rep(i, x, y) for (int i = x; i <= y; i ++)
#define Dwn(i, x, y) for (int i = x; i >= y; i --)
#define RepE(i, x) for(int i = pos[x]; i; i = g[i].nex)
#define u t[x]
#define o t[y]
#define Lc t[u.lc]
#define Rc t[u.rc]
#define eps 0.00000001
#define eps2 0.00001
using namespace std;
typedef long long LL;
typedef double DB;
const int N = 67000;
struct P { int lc, rc, fl; DB d[3], mx[3], mn[3]; } t[N * 2], b[N], a;
int n, m, ans, D, T, pos[N], rt, q; DB A, B, qr, lt;
bool operator< (P x, P y) { return x.d[D] < y.d[D]; }
DB sqr(DB x) { return x * x; }
DB f(DB x) { return A * x - B * sin(x); }
void F(DB &x, DB l = -100, DB r = 100) {
	while (l + eps < r) {
		DB mid = (l + r) / 2;
		if (f(mid * lt + 1) > x) r = mid;
		else l = mid;
	} x = (l + r) / 2;
}
int sqn(DB x, DB y) {
	if (x - y > 0.00001) return 1;
	return (x - y < -0.00001) ? -1 : 0;
}
DB Dis(P x, P y) { DB tmp = 0; Rep(i, 0, 2) tmp += sqr(x.d[i] - y.d[i]); return tmp; }
struct Kdtree
{
	DB Get(int x, P p) {
		DB tmp = 0; Rep(i, 0, 2) tmp += sqr( max(0.0, u.mn[i] - p.d[i]) + max(0.0, p.d[i] - u.mx[i]) );
		return tmp;
	}
	DB G2(int x, P p) {
		DB tmp = 0; Rep(i, 0, 2) tmp += sqr( max(u.mx[i] - p.d[i], p.d[i] - u.mn[i]) );
		return tmp;
	}
	void Upd(int x, int y) {
		Rep(i, 0, 2) u.mx[i] = max(u.mx[i], o.mx[i]), u.mn[i] = min(u.mn[i], o.mn[i]);
	}
	int Build(int l, int r, int now) {
		D = now; int x = l + r >> 1;
		nth_element(b + l, b + x, b + r + 1);
		u = b[x]; pos[ u.fl ] = x; Rep(i, 0, 2) u.mx[i] = u.mn[i] = u.d[i];
		if (l < x) u.lc = Build(l, x - 1, (now + 1) % 3), Upd(x, u.lc);
		if (x < r) u.rc = Build(x + 1, r, (now + 1) % 3), Upd(x, u.rc);
		return x;
	}
	void Add(int x, int now) {
		if (a.d[now] < u.d[now]) {
			if (u.lc) Add(u.lc, (now + 1) % 3);
			else {
				u.lc = ++ m, t[m] = a;
				Rep(i, 0, 2) t[m].mx[i] = t[m].mn[i] = t[m].d[i];
			} Upd(x, u.lc);
		} else {
			if (u.rc) Add(u.rc, (now + 1) % 3);
			else {
				u.rc = ++ m, t[m] = a;
				Rep(i, 0, 2) t[m].mx[i] = t[m].mn[i] = t[m].d[i];
			} Upd(x, u.rc);
		}
	}
	void Qry(int x) {
		if (!x || ans) return ;
		DB d0 = Dis(u, a);
		if (u.fl > 0 && sqn(d0, qr) == 0) { ans = u.fl; return ; }
		DB dl = Get(u.lc, a), dr = Get(u.rc, a), d1 = G2(u.lc, a), d2 = G2(u.rc, a);
		if (d1 < d2) {
			if (dl < qr + eps2 && d1 + eps2 > qr) Qry(u.lc); if (dr < qr + eps2 && d2 + eps2 > qr) Qry(u.rc);
		} else {
			if (dr < qr + eps2 && d2 + eps2 > qr) Qry(u.rc); if (dl < qr + eps2 && d1 + eps2 > qr) Qry(u.lc);
		}
	}
	void Del() {
		int x = pos[q]; u.fl = 0;
		Rep(i, 0, 2) u.mn[i] = Lc.mn[i], u.mx[i] = Lc.mx[i]; Upd(x, u.rc);
	}
} Kd;
int main()
{
	scanf ("%d%d%lf%lf", &n, &T, &A, &B);
	Rep(i, 1, n) {
		scanf ("%lf%lf%lf", &b[i].d[0], &b[i].d[1], &b[i].d[2]); b[i].fl = i;
	}
	rt = Kd.Build(1, n, 0); m = n, lt = 0.1;
	while (T --) {
		int ty; scanf ("%d", &ty);
		if (!ty) {
			DB tmp;
			scanf ("%lf%lf%lf%lf", &tmp, &a.d[0], &a.d[1], &a.d[2]);
			Rep(i, 0, 2) F(a.d[i]);
			F(tmp, 0, n), q = int(tmp + 0.5);
			a.fl = q; Kd.Del(), Kd.Add(rt, 0); pos[q] = m;
		} else {
			scanf ("%lf%lf%lf%lf", &a.d[0], &a.d[1], &a.d[2], &qr);
			Rep(i, 0, 2) F(a.d[i]); F(qr, -600, 600); qr = qr * qr;
			ans = 0, Kd.Qry(rt); printf("%d\n", ans); lt = ans;
		}
	}

	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值