KD - tree

對於 KK 維的點,用 BSTBST 維護
每一維交替劃分
注意暴力的剪枝
參考博客:[學習筆記] kd-tree


例題一:P4169 [Violet]天使玩偶/SJY擺棋子

多次操作,支持查詢曼哈頓距離最近的點 與 插入一個點
這題要開 O2O2 優化

#include<bits/stdc++.h>
#define rint register int
#define deb(x) cerr<<#x<<" = "<<(x)<<'\n';
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int maxn = 2e6 + 5;
const double alpha = 0.75;
int n, m, rt, tot, now, ans;
int sta[maxn], top;
struct node{
	int pla[2];
} a[maxn];
struct tree{
	int mx[2], mn[2], sz, ls, rs;
	node place;
} t[maxn];

inline int New(){
	if(top) return sta[top--];
	return ++tot;
}
inline bool cmp(const node &A, const node &B){
	return A.pla[now] < B.pla[now];
}

inline void update(int p){
	for(int i=0; i<=1; i++){
		t[p].mx[i] = t[p].mn[i] = t[p].place.pla[i];
		if(t[p].ls) t[p].mx[i] = max(t[p].mx[i], t[t[p].ls].mx[i]), \
					t[p].mn[i] = min(t[p].mn[i], t[t[p].ls].mn[i]);
		if(t[p].rs) t[p].mx[i] = max(t[p].mx[i], t[t[p].rs].mx[i]), \
					t[p].mn[i] = min(t[p].mn[i], t[t[p].rs].mn[i]);
	}
	t[p].sz = t[t[p].ls].sz + t[t[p].rs].sz + 1;
}

inline int build(int l, int r, int opt){
	if(l > r) return 0;
	int x = New(), mid = l + r >> 1; now = opt;
	nth_element(a+l, a+mid, a+r+1, cmp); t[x].place = a[mid];
	t[x].ls = build(l, mid-1, opt^1);
	t[x].rs = build(mid+1, r, opt^1);
	update(x); return x;
}

inline void pia(int p, int cnt){
	if(t[p].ls) pia(t[p].ls, cnt);
	a[cnt+t[t[p].ls].sz+1] = t[p].place, sta[++top] = p;
	if(t[p].rs) pia(t[p].rs, cnt+t[t[p].ls].sz+1);
}

inline void check(int &p, int opt){
	if(t[p].sz*alpha<t[t[p].ls].sz || t[p].sz*alpha<t[t[p].rs].sz)
		pia(p, 0), p = build(1, t[p].sz, opt);
}

inline void insert(node ret, int &p, int opt){
	if(!p){
		p = New(); t[p].place = ret;
		t[p].ls = t[p].rs = 0; 
		update(p); return;
	} 
	if(ret.pla[opt] <= t[p].place.pla[opt]) insert(ret, t[p].ls, opt^1);
	else insert(ret, t[p].rs, opt^1);
	update(p); check(p, opt);
}

inline int getdis(node a, int p){
	int ret = 0;
	for(int i=0; i<=1; i++) 
		ret += max(0, a.pla[i]-t[p].mx[i]) + max(0, t[p].mn[i]-a.pla[i]);
	return ret;
}
inline int dis(node a, node b){
	return abs(a.pla[0]-b.pla[0]) + abs(a.pla[1]-b.pla[1]);
}

inline void query(node ret, int p){
	ans = min(ans, dis(ret, t[p].place));
	int tmpl = inf, tmpr = inf;
	if(t[p].ls) tmpl = getdis(ret, t[p].ls);
	if(t[p].rs) tmpr = getdis(ret, t[p].rs);
	if(tmpl < tmpr){
		if(tmpl < ans) query(ret, t[p].ls);
		if(tmpr < ans) query(ret, t[p].rs);
	} else {
		if(tmpr < ans) query(ret, t[p].rs);
		if(tmpl < ans) query(ret, t[p].ls);
	}
}

int main() {
	scanf("%d%d", &n, &m);
	for(int i=1; i<=n; i++) scanf("%d%d", &a[i].pla[0], &a[i].pla[1]);
	rt = build(1, n, 0);
	for(int i=1; i<=m; i++){
		int opt; node ret;
		scanf("%d%d%d", &opt, &ret.pla[0], &ret.pla[1]);
		if(opt == 1) insert(ret, rt, 0);
		else ans = inf, query(ret, rt), printf("%d\n", ans);
	}
}

例題二:[Sdoi2010]Hide and Seek

查詢一個點的曼哈頓距離最大與最小的差值,的最小值

#include<bits/stdc++.h>
#define rint register int
#define deb(x) cerr<<#x<<" = "<<(x)<<'\n';
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int maxn = 2e6 + 5;
const double alpha = 0.75;
int n, m, rt, tot, now, ans;
int sta[maxn], top;
struct node{
	int pla[2];
} a[maxn];
struct tree{
	int mx[2], mn[2], sz, ls, rs;
	node place;
} t[maxn];

inline int New(){
	if(top) return sta[top--];
	return ++tot;
}
inline bool cmp(const node &A, const node &B){
	return A.pla[now] < B.pla[now];
}

inline void update(int p){
	for(int i=0; i<=1; i++){
		t[p].mx[i] = t[p].mn[i] = t[p].place.pla[i];
		if(t[p].ls) t[p].mx[i] = max(t[p].mx[i], t[t[p].ls].mx[i]), \
					t[p].mn[i] = min(t[p].mn[i], t[t[p].ls].mn[i]);
		if(t[p].rs) t[p].mx[i] = max(t[p].mx[i], t[t[p].rs].mx[i]), \
					t[p].mn[i] = min(t[p].mn[i], t[t[p].rs].mn[i]);
	}
	t[p].sz = t[t[p].ls].sz + t[t[p].rs].sz + 1;
}

inline int build(int l, int r, int opt){
	if(l > r) return 0;
	int x = New(), mid = l + r >> 1; now = opt;
	nth_element(a+l, a+mid, a+r+1, cmp); t[x].place = a[mid];
	t[x].ls = build(l, mid-1, opt^1);
	t[x].rs = build(mid+1, r, opt^1);
	update(x); return x;
}

inline void pia(int p, int cnt){
	if(t[p].ls) pia(t[p].ls, cnt);
	a[cnt+t[t[p].ls].sz+1] = t[p].place, sta[++top] = p;
	if(t[p].rs) pia(t[p].rs, cnt+t[t[p].ls].sz+1);
}

inline void check(int &p, int opt){
	if(t[p].sz*alpha<t[t[p].ls].sz || t[p].sz*alpha<t[t[p].rs].sz)
		pia(p, 0), p = build(1, t[p].sz, opt);
}

inline void insert(node ret, int &p, int opt){
	if(!p){
		p = New(); t[p].place = ret;
		t[p].ls = t[p].rs = 0; 
		update(p); return;
	} 
	if(ret.pla[opt] <= t[p].place.pla[opt]) insert(ret, t[p].ls, opt^1);
	else insert(ret, t[p].rs, opt^1);
	update(p); check(p, opt);
}

inline int getdis1(node a, int p){
	int ret = 0;
	for(int i=0; i<=1; i++) 
		ret += max(0, a.pla[i]-t[p].mx[i]) + max(0, t[p].mn[i]-a.pla[i]);
	return ret;
}
inline int getdis2(node a, int p){
	int ret = 0;
	for(int i=0; i<=1; i++) 
		ret += max(abs(a.pla[i]-t[p].mx[i]), abs(t[p].mn[i]-a.pla[i]));
	return ret;
}
inline int dis(node a, node b){
	return abs(a.pla[0]-b.pla[0]) + abs(a.pla[1]-b.pla[1]);
}

inline void query1(node ret, int p){
	if(dis(ret, t[p].place))
		ans = min(ans, dis(ret, t[p].place));
	int tmpl = inf, tmpr = inf;
	if(t[p].ls) tmpl = getdis1(ret, t[p].ls);
	if(t[p].rs) tmpr = getdis1(ret, t[p].rs);
	if(tmpl < tmpr){
		if(tmpl < ans) query1(ret, t[p].ls);
		if(tmpr < ans) query1(ret, t[p].rs);
	} else {
		if(tmpr < ans) query1(ret, t[p].rs);
		if(tmpl < ans) query1(ret, t[p].ls);
	}
}
inline void query2(node ret, int p){
	ans = max(ans, dis(ret, t[p].place));
	int tmpl = -inf, tmpr = -inf;
	if(t[p].ls) tmpl = getdis2(ret, t[p].ls);
	if(t[p].rs) tmpr = getdis2(ret, t[p].rs);
	if(tmpl > tmpr){
		if(tmpl > ans) query2(ret, t[p].ls);
		if(tmpr > ans) query2(ret, t[p].rs);
	} else {
		if(tmpr > ans) query2(ret, t[p].rs);
		if(tmpl > ans) query2(ret, t[p].ls);
	}
}

int main() {
	scanf("%d", &n);
	for(int i=1; i<=n; i++) scanf("%d%d", &a[i].pla[0], &a[i].pla[1]);
	rt = build(1, n, 0);
	int res = inf, mn, mx;
	for(int i=1; i<=n; i++){
		ans = inf;
		query1(a[i], rt), mn = ans;
		ans = -inf;
		query2(a[i], rt), mx = ans;
		res = min(res, mx - mn);
	}
	printf("%d\n", res);
}

例題三:P2093 [國家集訓隊]JZPFAR

歐式距離第 KK 遠,維護一個大小爲 KK 的堆

#include<bits/stdc++.h>
#define rint register int
#define deb(x) cerr<<#x<<" = "<<(x)<<'\n';
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int maxn = 2e6 + 5;
const double alpha = 0.75;
int n, m, rt, tot, now;
int sta[maxn], top;
struct node{
	int pla[2], id;
} a[maxn];
struct tree{
	int mx[2], mn[2], sz, ls, rs, id;
	node place;
} t[maxn];
struct Node{
	ll dis; int id;
	bool operator < (Node A) const {
		return dis == A.dis ? id < A.id : dis > A.dis;
	}
};
priority_queue <Node> q; 

inline int New(){
	if(top) return sta[top--];
	return ++tot;
}
inline bool cmp(const node &A, const node &B){
	return A.pla[now] < B.pla[now];
}

inline void update(int p){
	for(int i=0; i<=1; i++){
		t[p].mx[i] = t[p].mn[i] = t[p].place.pla[i];
		if(t[p].ls) t[p].mx[i] = max(t[p].mx[i], t[t[p].ls].mx[i]), \
					t[p].mn[i] = min(t[p].mn[i], t[t[p].ls].mn[i]);
		if(t[p].rs) t[p].mx[i] = max(t[p].mx[i], t[t[p].rs].mx[i]), \
					t[p].mn[i] = min(t[p].mn[i], t[t[p].rs].mn[i]);
	}
	t[p].sz = t[t[p].ls].sz + t[t[p].rs].sz + 1;
}

inline int build(int l, int r, int opt){
	if(l > r) return 0;
	int x = New(), mid = l + r >> 1; now = opt;
	nth_element(a+l, a+mid, a+r+1, cmp); 
	t[x].place = a[mid], t[x].id = a[mid].id;
	t[x].ls = build(l, mid-1, opt^1);
	t[x].rs = build(mid+1, r, opt^1);
	update(x); return x;
}

inline void pia(int p, int cnt){
	if(t[p].ls) pia(t[p].ls, cnt);
	a[cnt+t[t[p].ls].sz+1] = t[p].place, sta[++top] = p;
	if(t[p].rs) pia(t[p].rs, cnt+t[t[p].ls].sz+1);
}

inline void check(int &p, int opt){
	if(t[p].sz*alpha<t[t[p].ls].sz || t[p].sz*alpha<t[t[p].rs].sz)
		pia(p, 0), p = build(1, t[p].sz, opt);
}

inline void insert(node ret, int &p, int opt){
	if(!p){
		p = New(); t[p].place = ret;
		t[p].ls = t[p].rs = 0; 
		update(p); return;
	} 
	if(ret.pla[opt] <= t[p].place.pla[opt]) insert(ret, t[p].ls, opt^1);
	else insert(ret, t[p].rs, opt^1);
	update(p); check(p, opt);
}

inline ll pow2(ll x){ return x * x; }
inline ll getdis(node a, int p){
	ll ret = 0;
	for(int i=0; i<=1; i++) 
		ret += max(pow2(a.pla[i]-t[p].mx[i]), pow2(t[p].mn[i]-a.pla[i]));
	return ret;
}
inline ll dis(node a, node b){
	return pow2(a.pla[0]-b.pla[0]) + pow2(a.pla[1]-b.pla[1]);
}

inline void query(node ret, int p){
	ll dist =  dis(ret, t[p].place);
	ll tmpl = -inf, tmpr = -inf;
	if(t[p].ls) tmpl = getdis(ret, t[p].ls);
	if(t[p].rs) tmpr = getdis(ret, t[p].rs);
	if(dist>q.top().dis || (dist==q.top().dis && t[p].id<q.top().id)){
		q.pop();
		q.push({dist, t[p].id});
	}
	if(tmpl > tmpr){
		if(tmpl >= q.top().dis) query(ret, t[p].ls);
		if(tmpr >= q.top().dis) query(ret, t[p].rs);
	} else {
		if(tmpr >= q.top().dis) query(ret, t[p].rs);
		if(tmpl >= q.top().dis) query(ret, t[p].ls);
	}
}

int main() {
	scanf("%d", &n);
	for(int i=1; i<=n; i++) scanf("%d%d", &a[i].pla[0], &a[i].pla[1]), a[i].id = i;
	rt = build(1, n, 0);
	scanf("%d", &m);
	for(int i=1; i<=m; i++){
		int k; node ret;
		scanf("%d%d%d", &ret.pla[0], &ret.pla[1], &k);
		while(q.size()) q.pop();
		for(int i=1; i<=k; i++) q.push({-1, 0});
		query(ret, rt);
		printf("%d\n", q.top().id);
	}
}

例題四:[Cqoi2016]K遠點對

歐氏距離下的第 KK 遠點對, 維護一個大小爲 2K2K 的堆

#include<bits/stdc++.h>
#define rint register int
#define deb(x) cerr<<#x<<" = "<<(x)<<'\n';
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int maxn = 2e6 + 5;
const double alpha = 0.75;
int n, m, rt, tot, now;
int sta[maxn], top;
struct node{
	int pla[2], id;
} a[maxn];
struct tree{
	int mx[2], mn[2], sz, ls, rs;
	node place;
} t[maxn];
struct Node{
	ll dis;
	bool operator < (Node A) const {
		return dis > A.dis;
	}
};
priority_queue <Node> q; 

inline int New(){
	if(top) return sta[top--];
	return ++tot;
}
inline bool cmp(const node &A, const node &B){
	return A.pla[now] < B.pla[now];
}

inline void update(int p){
	for(int i=0; i<=1; i++){
		t[p].mx[i] = t[p].mn[i] = t[p].place.pla[i];
		if(t[p].ls) t[p].mx[i] = max(t[p].mx[i], t[t[p].ls].mx[i]), \
					t[p].mn[i] = min(t[p].mn[i], t[t[p].ls].mn[i]);
		if(t[p].rs) t[p].mx[i] = max(t[p].mx[i], t[t[p].rs].mx[i]), \
					t[p].mn[i] = min(t[p].mn[i], t[t[p].rs].mn[i]);
	}
	t[p].sz = t[t[p].ls].sz + t[t[p].rs].sz + 1;
}

inline int build(int l, int r, int opt){
	if(l > r) return 0;
	int x = New(), mid = l + r >> 1; now = opt;
	nth_element(a+l, a+mid, a+r+1, cmp); t[x].place = a[mid];
	t[x].ls = build(l, mid-1, opt^1);
	t[x].rs = build(mid+1, r, opt^1);
	update(x); return x;
}

inline void pia(int p, int cnt){
	if(t[p].ls) pia(t[p].ls, cnt);
	a[cnt+t[t[p].ls].sz+1] = t[p].place, sta[++top] = p;
	if(t[p].rs) pia(t[p].rs, cnt+t[t[p].ls].sz+1);
}

inline void check(int &p, int opt){
	if(t[p].sz*alpha<t[t[p].ls].sz || t[p].sz*alpha<t[t[p].rs].sz)
		pia(p, 0), p = build(1, t[p].sz, opt);
}

inline void insert(node ret, int &p, int opt){
	if(!p){
		p = New(); t[p].place = ret;
		t[p].ls = t[p].rs = 0; 
		update(p); return;
	} 
	if(ret.pla[opt] <= t[p].place.pla[opt]) insert(ret, t[p].ls, opt^1);
	else insert(ret, t[p].rs, opt^1);
	update(p); check(p, opt);
}

inline ll pow2(ll x){ return x * x; }
inline ll getdis(node a, int p){
	ll ret = 0;
	for(int i=0; i<=1; i++) 
		ret += max(pow2(a.pla[i]-t[p].mx[i]), pow2(t[p].mn[i]-a.pla[i]));
	return ret;
}
inline ll dis(node a, node b){
	return pow2(a.pla[0]-b.pla[0]) + pow2(a.pla[1]-b.pla[1]);
}

inline void query(node ret, int p){
	ll dist =  dis(ret, t[p].place);
	ll tmpl = -inf, tmpr = -inf;
	if(t[p].ls) tmpl = getdis(ret, t[p].ls);
	if(t[p].rs) tmpr = getdis(ret, t[p].rs);
	if(dist>q.top().dis){
		q.pop();
		q.push({dist});
	}
	if(tmpl > tmpr){
		if(tmpl >= q.top().dis) query(ret, t[p].ls);
		if(tmpr >= q.top().dis) query(ret, t[p].rs);
	} else {
		if(tmpr >= q.top().dis) query(ret, t[p].rs);
		if(tmpl >= q.top().dis) query(ret, t[p].ls);
	}
}

int main() {
	scanf("%d%d", &n, &m); m <<= 1;
	for(int i=1; i<=n; i++) scanf("%d%d", &a[i].pla[0], &a[i].pla[1]);
	rt = build(1, n, 0);
	for(int i=1; i<=m; i++) q.push({-1});
	for(int i=1; i<=n; i++){
		node ret = a[i];
		query(ret, rt);
	}
	printf("%lld\n", q.top().dis);
}
發佈了231 篇原創文章 · 獲贊 226 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章