KDT 板子,但被卡了。

const int N = 4e5 + 5, K = 2;
const ll inf = 1e16;

inline ll Read() {
	ll x = 0, f = 1;
	char c = getchar();
	while (c != '-' && (c < '0' || c > '9')) c = getchar();
	if (c == '-') f = -f, c = getchar();
	while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar();
	return x * f;
}

namespace Main {
	int n, k;
	int d;
	struct Point {
		ll x[K];
		bool operator < (const Point& b) const {
			return x[d] < b.x[d];
		}
	}a[N];
	priority_queue<ll> q;
#define sq(x) ((x) * (x))
	ll get_dis (Point a, Point b) { return sq(a.x[0] - b.x[0]) + sq(a.x[1] - b.x[1]); }
	struct KDT {
		struct node {
			int l, r;
			ll mx[K], mn[K];
			Point p;
		} t[N];
		int tot;
		ll limd (Point x, int y) {
			return max(sq(x.x[0] - t[y].mx[0]), sq(x.x[0] - t[y].mn[0])) + max(sq(x.x[1] - t[y].mx[1]), sq(x.x[1] - t[y].mn[1]));
		}
		void pushup (int p) {
			for(int i = 0; i < K; i++) t[p].mx[i] = t[p].mn[i] = t[p].p.x[i];
			if (t[p].l) {
				for(int i = 0; i < K; i++) t[p].mx[i] = max(t[p].mx[i], t[t[p].l].mx[i]);
				for(int i = 0; i < K; i++) t[p].mn[i] = min(t[p].mn[i], t[t[p].l].mn[i]);
			} 
		   	if (t[p].r) {
				for(int i = 0; i < K; i++) t[p].mx[i] = max(t[p].mx[i], t[t[p].r].mx[i]);
				for(int i = 0; i < K; i++) t[p].mn[i] = min(t[p].mn[i], t[t[p].r].mn[i]);
			}
		}
		void build (int &p, int l, int r, int curd) {
			if (l > r) return;
			p = ++tot;
			int mid = (l + r) >> 1;
			d = curd;
			nth_element(a + l, a + mid, a + r + 1);
			t[p].p = a[mid];
			build (t[p].l, l, mid - 1, curd ^ 1);
			build (t[p].r, mid + 1, r, curd ^ 1);
			pushup(p);
		}
		void query (int p, Point val) {
			if (!p) return;
			ll dl = -inf, dr = -inf;
			if (t[p].l) dl = limd(val, t[p].l);
			if (t[p].r) dr = limd(val, t[p].r);
			ll dis = get_dis(t[p].p, val);
			if(dis > -q.top())q.pop(), q.push(-dis);
			if(dl > dr) {
				if(dl > -q.top()) query(t[p].l, val);
				if(dr > -q.top()) query(t[p].r, val);
			} else {
				if(dr > -q.top()) query(t[p].r, val);
				if(dl > -q.top()) query(t[p].l, val);
			}
		}
	}t;
	int main () {
		n = Read(), k = Read();
		for (int i = 1; i <= n; i++) a[i].x[0] = Read(), a[i].x[1] = Read();
		int rt;
		t.build(rt, 1, n, 0);
		for(int i = 1; i <= 2 * k; i++)q.push(0);
		for(int i = 1; i <= n; i++) t.query(1, a[i]);
		printf("%lld\n", -q.top());
		return 0;
	}
}

int main () {
//	freopen(".in", "r", stdin);
//	freopen(".out", "w", stdout);
	Main::main();
	return 0;
}

还可以旋转卡壳。

与 KDT 类似,也是维护一个大 $k$ 的小根堆,每次取最远的放入。

具体地,每次旋转卡壳取相隔最远的两个点,把所有点和这两个点的距离丢进小根堆里,然后把这两个点删掉,这个过程重复 $k$ 次。

const int N = 4e5 + 5, K = 2;
const ll inf = 1e16;

inline ll Read() {
	ll x = 0, f = 1;
	char c = getchar();
	while (c != '-' && (c < '0' || c > '9')) c = getchar();
	if (c == '-') f = -f, c = getchar();
	while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar();
	return x * f;
}

namespace Main {
	struct node {
		ll x, y, id;
	} p[N], s[N];
	ll n, k, siz, tmp, top, ans;
	bool vis[N];
	priority_queue<ll, vector<ll>, greater<ll> >q;
	inline bool cmp(node a, node b) { return a.x != b.x ? a.x < b.x : a.y < b.y; }
	inline ll dist(node a, node b) { return (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y); }
	inline ll cross(node a, node b, node c) { return (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x); }
	inline void insert(ll x) {
		if(siz < k)siz++, q.push(x);
		else if(siz >= k && q.top() < x)q.pop(), q.push(x);
	}
	inline void del(ll x) {
		vis[x] = 1;
		for(ll i = 1; i <= n; i++)if(!vis[i])insert(dist(p[i], p[x]));
	}
	inline void init() {
		top = 0;
		for(ll i = 1; i <= n; i++) {
			if(vis[i])continue;
			for(; top >= 2 && cross(s[top - 1], s[top], p[i]) >= 0; top--);
			s[++top] = p[i];
		}
		for(ll i = s[top].id - 1, pre = top; i >= s[1].id; i--) {
			if(vis[i])continue;
			for(; top - pre >= 1 && cross(s[top - 1], s[top], p[i]) >= 0; top--);
			s[++top] = p[i];
		}
		s[0] = s[--top];
	}
	inline node Find() {
		init();
		ll ans = 0, a1, a2;
		if(top == 2) {
			return (node) {
				s[1].id, s[2].id
			};
		}
		for(ll i = 0, j = 2; i < top; i++) {
			while(cross(s[i], s[i + 1], s[j]) > cross(s[i], s[i + 1], s[j + 1]))j = (j + 1) % top;
			if(dist(s[i], s[j]) > ans)ans = dist(s[i], s[j]), a1 = s[i].id, a2 = s[j].id;
			if(dist(s[i + 1], s[j]) > ans)ans = dist(s[i + 1], s[j]), a1 = s[i + 1].id, a2 = s[j].id;
		}
		return (node) { a1, a2 };
	}
	int main() {
		n = tmp = Read(), k = Read();
		for(int i = 1; i <= n; i++)p[i].x = Read(), p[i].y = Read();
		sort(p + 1, p + n + 1, cmp);
		for(int i = 1; i <= n; i++)p[i].id = i;
		for(; k && tmp >= 2; k--, tmp -= 2) {
			node a = Find();
			del(a.x); del(a.y);
		}
		printf ("%lld", q.top());
		return 0;
	}
}

int main () {
//	freopen(".in", "r", stdin);
//	freopen(".out", "w", stdout);
	Main::main();
	return 0;
}
EOF

评论

暂无评论

发表评论

可以用@mike来提到mike这个用户,mike会被高亮显示。如果你真的想打“@”这个字符,请用“@@”。

博客信息

作者
Jayun
时间
2023-11-13 21:50:47
博客类型