最近看了一下k-NN而後它說若是特徵空間維數比較低的時候用K-D Tree來求k近鄰比較快因此就來補一下學OI時沒學的K-D Tree僞裝寫一個學習筆記吧。php
是一個平衡二叉樹node
k=1的時候就是一隻BSTios
k>1的話,每一層換一維來分割學習
就是用許多垂直座標軸的超平面將一個k維空間分割ui
每一個節點保存了一個點,它所表明的超平面就是通過這個點垂直於某個座標軸一個超平面spa
每一個子樹表明了一個區域(代碼實現中是包含子樹中全部點的最小超矩形,實際上應該是劃分後的那個超矩形code
我沒有任何建樹,下一個ci
複雜度\(O(kn\log n)\),一個分治...element
直接插入就好了,注意一路updateget
挺不科學的插入的話會破壞建樹時的平衡性
因此要加入重構好麻煩不想寫
有點詭異的啓發式搜索
有一個估算一個點到一個超矩形的最大/最小距離的操做
對於最近鄰來講,先搜左右兒子中距離近的,而且只搜估算最近距離小於當前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; }