社区讨论

KDT 做法求助

P14957【模板】离线静态四维数点参与者 5已保存回复 8

讨论操作

快速查看讨论及其快照的属性,并进行相关操作。

当前回复
8 条
当前快照
1 份
快照标识符
@mk10skcc
此快照首次捕获于
2026/01/05 18:30
上个月
此快照最后确认于
2026/01/08 23:55
上个月
查看原帖
不是 4DT,一维排序一维树状数组两维 KDT。
复杂度分析出来是对的,在程序里算出来理论次数也是对的。但是查询一次访问的实际次数远大于 O(n)\mathcal{O}(\sqrt n) 了,求助一下是怎么回事 /kel
已经排除了重复的点导致复杂度分析错误这个可能性。
CPP
#include <bits/stdc++.h>
 
using namespace std;

typedef array<int, 2> pnt;
 
const int MAXN = 4e5 + 10;

struct node {
	int l, r, w, s; pnt x, tl, tr;
	node(pnt x = {}) : l(0), r(0), w(0), s(0), x(x), tl(x), tr(x) {}
} t[MAXN * 19]; int rt[MAXN], cnt, a[MAXN];

inline 
void pushup(int p) {
	t[p].tl = t[p].tr = t[p].x;
	if (t[p].l) {
		for (int i = 0; i < 2; i++) t[p].tl[i] = min(t[p].tl[i], t[t[p].l].tl[i]);
		for (int i = 0; i < 2; i++) t[p].tr[i] = max(t[p].tr[i], t[t[p].l].tr[i]);
	}
	if (t[p].r) {
		for (int i = 0; i < 2; i++) t[p].tl[i] = min(t[p].tl[i], t[t[p].r].tl[i]);
		for (int i = 0; i < 2; i++) t[p].tr[i] = max(t[p].tr[i], t[t[p].r].tr[i]);
	}
}

int build(int l, int r, int k = 0) {
	if (l > r) return 0; int mid = l + r >> 1;
	nth_element(a + l, a + mid, a + r + 1, [k](int i, int j) { return t[i].x[k] < t[j].x[k]; });
	int p = a[mid]; t[p].l = build(l, mid - 1, k ^ 1), t[p].r = build(mid + 1, r, k ^ 1);
	return pushup(p), p;
}

void add(pnt x, int p) {
	if (!p) return ;
	if (x[0] < t[p].tl[0] || x[0] > t[p].tr[0]) return ;
	if (x[1] < t[p].tl[1] || x[1] > t[p].tr[1]) return ;
	t[p].s++;
	if (x[0] == t[p].x[0] && x[1] == t[p].x[1]) return t[p].w++, void();
	add(x, t[p].l), add(x, t[p].r);
}

int __cnt;

int ask(pnt x, int p) {
	__cnt++;
	if (!p) return 0;
	if (x[0] > t[p].tr[0] || x[1] > t[p].tr[1]) return 0;
	if (x[0] <= t[p].tl[0] && x[1] <= t[p].tl[1]) return t[p].s;
	if (x[0] > t[p].x[0] || x[1] > t[p].x[1]) return ask(x, t[p].l) + ask(x, t[p].r);
	return t[p].w + ask(x, t[p].l) + ask(x, t[p].r);
}

int n, m, b[MAXN];

inline 
void tadd(int k, pnt x) {
	for (int i = k; i <= n; i += i & -i) add(x, rt[i]);
}

inline 
int task(int k, pnt x) {
	int res = 0; __cnt = 0;
	for (int i = k; i; i &= i - 1) res += ask(x, rt[i]);
	assert(__cnt <= 5000); // 就这玩意。n<=2e5 都会 assert 失败。
	return res;
}

struct qnode {
	int a, b, c, d, id;
	qnode(int a = 0, int b = 0, int c = 0, int d = 0, int id = 0) :
		a(a), b(b), c(c), d(d), id(id) {}
	bool operator < (const qnode &rhs) const { return a == rhs.a ? id < rhs.id : a < rhs.a; }
} q[MAXN << 1];

int ans[MAXN], id[MAXN], rk[MAXN];

int main() {
	scanf("%d%d", &n, &m);
	for (int i = 1, a, b, c, d; i <= n; i++) {
		scanf("%d%d%d%d", &a, &b, &c, &d);
		::b[i] = b, q[i] = qnode(a, b, c, d, -i);
	}
	for (int i = 1, a, b, c, d; i <= m; i++) {
		scanf("%d%d%d%d", &a, &b, &c, &d);
		q[n + i] = qnode(a, b, c, d, i);
	}
	sort(b + 1, b + n + 1);
	for (int i = 1; i <= n; i++) id[i] = i;
	sort(id + 1, id + n + 1, [](int i, int j) { return q[i].b < q[j].b; });
	for (int i = 1; i <= n; i++) rk[id[i]] = i;
	for (int i = 1; i <= n; i++) {
		int len = i & -i;
		for (int j = 1; j <= len; j++) {
			int k = id[i - j + 1];
			t[++cnt] = pnt({ q[k].c, q[k].d }), a[j] = cnt;
		}
		rt[i] = build(1, len);
	}
	sort(q + 1, q + n + m + 1);
	for (int i = 1; i <= n + m; i++) {
		if (q[i].id < 0) tadd(rk[-q[i].id], pnt({ q[i].c, q[i].d }));
		else {
			int j = upper_bound(::b + 1, ::b + n + 1, q[i].b) - ::b - 1;
			ans[q[i].id] = task(j, pnt({ q[i].c, q[i].d }));
		}
	}
	for (int i = 1; i <= m; i++) printf("%d\n", ans[i]);
}

回复

8 条回复,欢迎继续交流。

正在加载回复...