K-D Tree题目泛做(CXJ第二轮)

时间:2023-03-10 02:02:34
K-D Tree题目泛做(CXJ第二轮)

题目1: BZOJ 2716

题目大意:给出N个二维平面上的点,M个操作,分为插入一个新点和询问到一个点最近点的Manhatan距离是多少。

算法讨论:

K-D Tree 裸题,有插入操作。

 #include <cstdio>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <algorithm> using namespace std; const int inf = 1e9;
const int K = ;
const int N = + ; inline int read() {
int x = ;
char ch = getchar(); while(ch < '' || ch > '') ch = getchar();
while(ch <= '' && ch >= '') {
x = x * + ch - '';
ch = getchar();
}
return x;
} int n, m, root, D, ans; struct Node {
int d[K], mn[K], mx[K], l, r, v, sum; int & operator [] (int x) {
return d[x];
}
Node(int x = , int y = ) {
l = ; r = ; d[] = x; d[] = y;
}
friend bool operator < (Node a, Node b) {
return a[D] < b[D];
}
}p[N], T[N<<], tmp; void pushup(int k) {
Node l = T[T[k].l], r = T[T[k].r]; for(int i = ; i < K; ++ i) {
T[k].mn[i] = T[k].mx[i] = T[k][i];
if(T[k].l) {
T[k].mn[i] = min(T[k].mn[i], l.mn[i]);
T[k].mx[i] = max(T[k].mx[i], l.mx[i]);
}
if(T[k].r) {
T[k].mx[i] = max(T[k].mx[i], r.mx[i]);
T[k].mn[i] = min(T[k].mn[i], r.mn[i]);
}
}
// T[k].sum = T[k].v;
// if(T[k].l) T[k].sum += l.sum;
// if(T[k].r) T[k].sum += r.sum;
} int build(int l, int r, int nd) {
int mid = (l + r) >> ; D = nd;
nth_element(p + l, p + mid, p + r + );
T[mid] = p[mid];
T[mid].l = T[mid].r = ;
for(int i = ; i < K; ++ i)
T[mid].mx[i] = T[mid].mn[i] = T[mid][i];
if(l < mid)
T[mid].l = build(l, mid - , (nd + ) % K);
if(r > mid)
T[mid].r = build(mid + , r, (nd + ) % K);
pushup(mid);
return mid;
} void insert(int k, int nd) {
if(tmp[nd] >= T[k][nd]) {
if(T[k].r) insert(T[k].r, (nd + ) % K);
else {
T[k].r = ++ n;
T[n] = tmp;
for(int i = ; i < K; ++ i)
T[n].mn[i] = T[n].mx[i] = T[n][i];
}
}
else {
if(T[k].l) insert(T[k].l, (nd + ) % K);
else {
T[k].l = ++ n;
T[n] = tmp;
for(int i = ; i < K; ++ i)
T[n].mn[i] = T[n].mx[i] = T[n][i];
}
}
pushup(k);
} int getkdis(Node a, Node b) {
int res = ; for(int i = ; i < K; ++ i)
res += abs(a[i] - b[i]);
return res;
} int inandout(int k, Node a) {
int res = ; for(int i = ; i < K; ++ i)
res += max(, T[k].mn[i] - a[i]);
for(int i = ; i < K; ++ i)
res += max(, a[i] - T[k].mx[i]);
return res;
} void query(int k, int nd) {
int d, dl = inf, dr = inf; d = getkdis(T[k], tmp);
if(d) ans = min(ans, d);
if(T[k].l) dl = inandout(T[k].l, tmp);
if(T[k].r) dr = inandout(T[k].r, tmp);
if(dl < dr) {
if(dl < ans) query(T[k].l, (nd + ) % K);
if(dr < ans) query(T[k].r, (nd + ) % K);
}
else {
if(dr < ans) query(T[k].r, (nd + ) % K);
if(dl < ans) query(T[k].l, (nd + ) % K);
}
} int query(Node a) {
tmp = a; ans = inf;
query(root, );
return ans;
} void insert(Node a) {
tmp = a; insert(root, );
}
#define ONLINE_JUDGE
int main() {
#ifndef ONLINE_JUDGE
freopen("1.in", "r", stdin);
freopen("1.out", "w", stdout);
#endif int type, x, y; n = read(); m = read();
for(int i = ; i <= n; ++ i)
p[i][] = read(), p[i][] = read();
root = build(, n, );//忘记写root等于了。
for(int i = ; i <= m; ++ i) {
type = read(); x = read(); y = read();
if(type == ) insert(Node(x, y));
else printf("%d\n", query(Node(x, y)));
} #ifndef ONLINE_JUDGE
fclose(stdin); fclose(stdout);
#endif
return ;
}

BZOJ 2716

题目2: BZOJ 1941

题目大意:给出N个点,求对于每个点说,Manhantan距离最远点与最近点的差值最小是多少。

算法讨论:

K-D Tree裸题,注意最近点不能是自己。

 #include <cstdio>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <algorithm> using namespace std; const int N = + ;
const int inf = 1e9;
const int K = ; inline int read() {
int x = ;
char ch = getchar(); while(ch < '' || ch > '') ch = getchar();
while(ch <= '' && ch >= '') {
x = x * + ch - '';
ch = getchar();
}
return x;
} int n, root, amax, amin, D; struct Node {
int d[K], mn[K], mx[K], l, r; int & operator [] (int x) {
return d[x];
}
Node (int x = , int y = ) {
l = ; r = ; d[] = x; d[] = y;
}
friend bool operator < (Node a, Node b) {
return a[D] < b[D];
}
}p[N], T[N<<], tmp; void pushup(int k) {
Node l = T[T[k].l], r = T[T[k].r]; for(int i = ; i < K; ++ i) {
T[k].mn[i] = T[k].mx[i] = T[k][i];
if(T[k].l) {
T[k].mx[i] = max(T[k].mx[i], l.mx[i]);
T[k].mn[i] = min(T[k].mn[i], l.mn[i]);
}
if(T[k].r) {
T[k].mx[i] = max(T[k].mx[i], r.mx[i]);
T[k].mn[i] = min(T[k].mn[i], r.mn[i]);
}
}
} int build(int l, int r, int nd) {
int mid = (l + r) >> ; D = nd;
nth_element(p + l, p + mid, p + r + );
T[mid] = p[mid];
T[mid].l = T[mid].r = ;
for(int i = ; i < K; ++ i)
T[mid].mn[i] = T[mid].mx[i] = T[mid][i];
if(l < mid) T[mid].l = build(l, mid - , (D + ) % K);
if(r > mid) T[mid].r = build(mid + , r, (D + ) % K);
pushup(mid);
return mid;
} void insert(int k, int nd) {
if(tmp[nd] >= T[k][nd]) {
if(T[k].r) insert(T[k].r, (nd + ) % K);
else {
T[k].r = ++ n;
T[n] = tmp;
for(int i = ; i < K; ++ i)
T[n].mx[i] = T[n].mn[i] = T[n][i];
}
}
else {
if(T[k].l) insert(T[k].l, (nd + ) % K);
else {
T[k].l = ++ n;
T[n] = tmp;
for(int i = ; i < K; ++ i)
T[n].mx[i] = T[n].mn[i] = T[n][i];
}
}
pushup(k);
} int getkdis(Node a, Node b) {
int res = ; for(int i = ; i < K; ++ i)
res += abs(a[i] - b[i]);
return res;
} int outandin(int k, Node q) {
int res = ; for(int i = ; i < K; ++ i)
res += max(, T[k].mn[i] - q[i]);
for(int i = ; i < K; ++ i)
res += max(, q[i] - T[k].mx[i]);
return res;
} int outandinmaxx(int k, Node q) {
int res = ; for(int i = ; i < K; ++ i)
res += max(abs(T[k].mn[i] - q[i]), abs(T[k].mx[i] - q[i]));
return res;
} void query_maxx(int k, int nd) {
int d, dl = -inf, dr = -inf; d = getkdis(T[k], tmp);
amax = max(d, amax);
if(T[k].l) dl = outandinmaxx(T[k].l, tmp);
if(T[k].r) dr = outandinmaxx(T[k].r, tmp);
if(dl > dr) {
if(dl > amax) query_maxx(T[k].l, (nd + ) % K);
if(dr > amax) query_maxx(T[k].r, (nd + ) % K);
}
else {
if(dr > amax) query_maxx(T[k].r, (nd + ) % K);
if(dl > amax) query_maxx(T[k].l, (nd + ) % K);
}
} void query_minn(int k, int nd) {
int d, dl = inf, dr = inf; d = getkdis(T[k], tmp);
if(d) amin = min(d, amin);
if(T[k].l) dl = outandin(T[k].l, tmp);
if(T[k].r) dr = outandin(T[k].r, tmp);
if(dl < dr) {
if(dl < amin) query_minn(T[k].l, (nd + ) % K);
if(dr < amin) query_minn(T[k].r, (nd + ) % K);
}
else {
if(dr < amin) query_minn(T[k].r, (nd + ) % K);
if(dl < amin) query_minn(T[k].l, (nd + ) % K);
}
} void qmax(int l) {
amax = -inf; tmp = p[l];
query_maxx(root, ); } void qmin(int l) {
amin = inf; tmp = p[l];
query_minn(root, );
} int main() {
int outans = inf; n = read();
for(int i = ; i <= n; ++ i) {
p[i][] = read(); p[i][] = read();
}
root = build(, n, );
for(int i = ; i <= n; ++ i) {
qmax(i); qmin(i);
outans = min(outans, amax - amin);
}
printf("%d\n", outans);
return ;
}

BZOJ 1941

题目3: BZOJ4520 && CQOI 2016 K远点对查询

题目大意:

给出n个二维平面上的点,求第k远的点对距离是多少。(欧几里德距离的平方)

算法讨论:

1、为了防止重复,小根堆里面保存2*K个元素。

2、编程习惯一定要好。同类型比较,减少强制类型转制。在查询欧几里德距离的时候,query中的维度参数是没有用的。

果断要去掉。否则就是TLE和AC的区别。

要区分好查询欧几里德距离和曼哈顿距离时两者的区别。

代码:

#include <cstdlib>
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cctype>
#include <queue>
#include <vector> using namespace std;
typedef long long ll;
const int N = 100000 + 5;
const int K = 2;
const ll inf = 10000000000000LL;
inline int read() {
int x = 0; char c = getchar();
while(!isdigit(c)) c = getchar();
while(isdigit(c)) {
x = x * 10 + c - '0';
c = getchar();
}
return x;
}
int buf[20];
inline void output(ll x) {
int p = 0; buf[0] = 0;
if(!x) p ++;
else {
while(x) {
buf[p ++] = x % 10;
x /= 10;
}
}
for(int i = p - 1; i >= 0; -- i)
putchar(buf[i] + '0');
} int root, n, kk, D;
priority_queue <ll, vector<ll>, greater<ll> > ans; struct Node {
int l, r;
ll d[K], mn[K], mx[K];
Node(ll x = 0, ll y = 0) {
l = r = 0; d[0] = x; d[1] = y;
}
ll & operator [] (int x) { return d[x];}
friend bool operator < (Node a, Node b) {
return a[D] < b[D];
}
}p[N], T[N << 1], tmp; void pushup(int k) {
Node l = T[T[k].l], r = T[T[k].r];
for(int i = 0; i < K; ++ i) {
T[k].mx[i] = T[k].mn[i] = T[k][i];
if(T[k].l) {
T[k].mx[i] = max(T[k].mx[i], l.mx[i]);
T[k].mn[i] = min(T[k].mn[i], l.mn[i]);
}
if(T[k].r) {
T[k].mx[i] = max(T[k].mx[i], r.mx[i]);
T[k].mn[i] = min(T[k].mn[i], r.mn[i]);
}
}
} int build(int l, int r, int nd) {
int mid = (l + r) >> 1;
D = nd;
nth_element(p + l, p + mid, p + r + 1);
T[mid] = p[mid];
T[mid].l = T[mid].r = 0;
for(int i = 0; i < K; ++ i)
T[mid].mx[i] = T[mid].mn[i] = T[mid][i];
if(l < mid) T[mid].l = build(l, mid - 1, (nd + 1) % K);
if(r > mid) T[mid].r = build(mid + 1, r, (nd + 1) % K);
pushup(mid);
return mid;
} ll geteulerdis(Node a, Node b) {//竭诚为欧几里德距离服务
ll res = 0;
for(int i = 0; i < K; ++ i)
res += (a[i] - b[i]) * (a[i] - b[i]);
return res;
} ll outandineuler(Node a) {
ll L = 0;
L = max(L, geteulerdis(tmp, Node(a.mx[0], a.mn[1])));
L = max(L, geteulerdis(tmp, Node(a.mx[0], a.mx[1])));
L = max(L, geteulerdis(tmp, Node(a.mn[0], a.mn[1])));
L = max(L, geteulerdis(tmp, Node(a.mn[0], a.mx[1])));
return L;
} void query(int k) {
ll d, dl = -inf, dr = -inf;
d = geteulerdis(T[k], tmp);
if(d > ans.top()) {
ans.pop(); ans.push(d);
}
if(T[k].l) dl = outandineuler(T[T[k].l]);
if(T[k].r) dr = outandineuler(T[T[k].r]);
if(dl > dr) {
if(dl > ans.top()) query(T[k].l);
if(dr > ans.top()) query(T[k].r);
}
else {
if(dr > ans.top()) query(T[k].r);
if(dl > ans.top()) query(T[k].l);
}
} void Q(int i) {
tmp = p[i];
query(root);
} int main() {
n = read(); kk = read();
for(int i = 1; i <= 2 * kk; ++ i) ans.push(0);
for(int i = 1; i <= n; ++ i) {
p[i][0] = read(); p[i][1] = read();
}
root = build(1, n, 0);
for(int i = 1; i <= n; ++ i) Q(i);
output(ans.top());
return 0;
}