K-D Tree 学习笔记
K-D Tree 學習筆記
最近看了一下k-NN然后它說如果特征空間維數比較低的時候用K-D Tree來求k近鄰比較快所以就來補一下學OI時沒學的K-D Tree假裝寫一個學習筆記吧。
是什么?
是一個平衡二叉樹
k=1的時候就是一只BST
k>1的話,每一層換一維來分割
就是用許多垂直坐標軸的超平面將一個k維空間分割
每個節(jié)點保存了一個點,它所代表的超平面就是經過這個點垂直于某個坐標軸一個超平面
每個子樹代表了一個區(qū)域(代碼實現中是包含子樹中所有點的最小超矩形,實際上應該是劃分后的那個超矩形
怎么做?
建樹
我沒有任何建樹,下一個
復雜度\(O(kn\log n)\),一個分治...
插入
直接插入就行了,注意一路update
挺不科學的插入的話會破壞建樹時的平衡性
所以要加入重構好麻煩不想寫
查詢
有點詭異的啟發(fā)式搜索
有一個估算一個點到一個超矩形的最大/最小距離的操作
對于最近鄰來說,先搜左右兒子中距離近的,并且只搜估算最近距離小于當前ans的
k近鄰的話,用個大根堆,一直保持堆中有k個的元素
遠的話換成遠就行了QwQ
聽說隨機數據復雜度\(O(\log n)\)到\(O(n\sqrt{n})\) ,不會證不會證
代碼實現
因為早就退役了所以我也沒有做很多題來練習各種鬼畜用法的必要了扔模板就跑
bzoj2648 帶插入最近鄰
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <vector> using namespace std; const int N = 1e6+5, inf = 1e9; #define lc t[x].ch[0] #define rc t[x].ch[1] #define max0(x) max(x, 0)int n, m; int curD = 0; struct meow {int d[2];meow() {}meow(int x, int y){d[0]=x; d[1]=y;}bool operator < (const meow &r) const {return d[curD] < r.d[curD];}int calDist(meow &a) {return abs(d[0] - a.d[0]) + abs(d[1] - a.d[1]);} }; meow a[N]; struct node {int ch[2], x[2], y[2];meow p;void update(node &a) {x[0] = min(x[0], a.x[0]); x[1] = max(x[1], a.x[1]);y[0] = min(y[0], a.y[0]); y[1] = max(y[1], a.y[1]);}void set(meow &a) {p = a;x[0] = x[1] = a.d[0];y[0] = y[1] = a.d[1];}int evaDist(meow &a) {int xx = a.d[0], yy = a.d[1];return max0(x[0] - xx) + max0(xx - x[1]) + max0(y[0] - yy) + max0(yy - y[1]);} } t[N]; int root; int build(int l, int r, int d) {curD = d;int x = (l+r)>>1;nth_element(a+l, a+x, a+r+1);t[x].set(a[x]);if(l < x) lc = build(l, x-1, d^1), t[x].update(t[lc]);if(x < r) rc = build(x+1, r, d^1), t[x].update(t[rc]);return x; } void insert(meow q) {t[++n].set(q);for(int x=root, D=0; x; D^=1) {t[x].update(t[n]);int &nxt = t[x].ch[q.d[D] >= t[x].p.d[D]];if(nxt == 0) {nxt = n;break;}else x = nxt;} }int ans; void query(int x, meow q) {int nowDist = t[x].p.calDist(q), d[2];d[0] = lc ? t[lc].evaDist(q) : inf;d[1] = rc ? t[rc].evaDist(q) : inf;int wh = d[1] <= d[0];ans = min(ans, nowDist);if(d[wh] < ans) query(t[x].ch[wh], q);wh ^= 1;if(d[wh] < ans) query(t[x].ch[wh], q); }int main() {cin >> n >> m;int c, x, y;for(int i=1; i<=n; i++) {scanf("%d %d", &x, &y);a[i] = meow(x, y);}root = build(1, n, 0);for(int i=1; i<=m; i++) {scanf("%d %d %d", &c, &x, &y);if(c == 1) insert(meow(x, y));else {ans = inf;query(root, meow(x, y));printf("%d\n", ans);}} }bzoj4520 k遠點對
每個點求一次k遠點
值得注意的是會TLE所以整體用一個大根堆才行
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <vector> #include <ctime> #include <queue> using namespace std; typedef long long ll; const int N = 1e5+5; const ll inf = 1e18; #define lc t[x].ch[0] #define rc t[x].ch[1] #define max0(x) max(x, 0)inline ll sqr(ll x) {return x*x;}int n, K; int curD = 0; struct meow {ll d[2];meow() {}meow(ll x, ll y){d[0]=x; d[1]=y;}bool operator < (const meow &r) const {//if(d[curD] == r.d[curD]) return d[curD^1] < r.d[curD^1];return d[curD] < r.d[curD];}ll calDist(meow &a) {//return abs(d[0] - a.d[0]) + abs(d[1] - a.d[1]);return sqr(d[0] - a.d[0]) + sqr(d[1] - a.d[1]);} }; meow a[N]; struct node {int ch[2], x[2], y[2];meow p;void update(node &a) {x[0] = min(x[0], a.x[0]);x[1] = max(x[1], a.x[1]);y[0] = min(y[0], a.y[0]);y[1] = max(y[1], a.y[1]);}void set(meow &a) {p = a;x[0] = x[1] = a.d[0];y[0] = y[1] = a.d[1];}ll evaMaxDist(meow &a) {ll xx = a.d[0], yy = a.d[1];return max(sqr(x[0]-xx), sqr(x[1]-xx)) + max(sqr(y[0]-yy), sqr(y[1]-yy));} } t[N]; int root; int build(int l, int r, int d) {curD = d;int x = (l+r)>>1;nth_element(a+l, a+x, a+r+1);t[x].set(a[x]);if(l < x) {lc = build(l, x-1, d^1);t[x].update(t[lc]);}if(x < r) {rc = build(x+1, r, d^1);t[x].update(t[rc]);}return x; }priority_queue<ll, vector<ll>, greater<ll> > ans; void query(int x, meow q) {ll nowDist = t[x].p.calDist(q), d[2];d[0] = lc ? t[lc].evaMaxDist(q) : -inf;d[1] = rc ? t[rc].evaMaxDist(q) : -inf;int wh = d[1] >= d[0];if(nowDist > ans.top()) ans.pop(), ans.push(nowDist);if(d[wh] > ans.top()) query(t[x].ch[wh], q);wh ^= 1;if(d[wh] > ans.top()) query(t[x].ch[wh], q); }int main() {cin >> n >> K; K <<= 1;int x, y;for(int i=1; i<=n; i++) {scanf("%d %d", &x, &y);a[i] = meow(x, y);}root = build(1, n, 0);for(int j=1; j<=K; j++) ans.push(-inf);for(int i=1; i<=n; i++) {query(root, a[i]);} cout << ans.top() << endl; }轉載于:https://www.cnblogs.com/candy99/p/10346870.html
總結
以上是生活随笔為你收集整理的K-D Tree 学习笔记的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: c++中的::符
- 下一篇: “华为杯”——中国研究生数学建模大赛相关