题目大意:
给你二维平面上一些旅馆,每个都有一个价格p,然后询问距离一个点,价格不高于p的旅店最近的是哪一个?
首先如果考虑可修改的话,大家很明显可以想到可以kd-tree解决对吧,就是按价格排序,然后逐步插入。但是这么做常数太大了,不说要排序好几次,还要承担树重构的一个常数,这题还是卡的很好的,至少我被卡了常数,就很迷茫,感觉写法上自己还是有改进的地方,被卡常数了,也要知道这个算法的常数到底大不大才行,
然后这道题其实就是把在线的东西,做成离线的就行了,先把所有点插入,然后我们怎么筛选价格呢,我们就在距离函数里加一条比较价格的就可以。虽然这种不是三维的,但是如果构造一种卡这种算法的数据也是很难的。虽然复杂度可能会有跑一些没用的点,但是实际还是很快的,没那么容易跑到上界。
而且这题还让我学到一个东西,算欧式距离的时候,可以先不开根号,先留着,要不然sqrt的常数也不小。
#pragma GCC optimize(2) #include<iostream> #include<cstdio> #include<algorithm> #include<vector> #include<cmath> #define alpha (0.75) using namespace std; typedef pair<int, pair<int, int>> P; typedef long long ll; const int N = 2e5 + 5; const ll INF = 1e16; bool dimension; bool reg_dimension; int n, m,ans_num; ll ans; struct Point { ll x, y; int p,num; Point(int X = 0, int Y = 0,int P=0) :x(X), y(Y),p(P) {} }; Point a[N]; struct Node *null; struct Node { int cover; Point p, r1, r2; Node *son[2]; inline void maintain() { r1.x = min(r1.x, min(son[0]->r1.x, son[1]->r1.x)); r1.y = min(r1.y, min(son[0]->r1.y, son[1]->r1.y)); r1.p = min(r1.p, min(son[0]->r1.p, son[1]->r1.p)); r2.x = max(r2.x, max(son[0]->r2.x, son[1]->r2.x)); r2.y = max(r2.y, max(son[0]->r2.y, son[1]->r2.y)); r2.p = max(r2.p, max(son[0]->r2.p, son[1]->r2.p)); cover = son[0]->cover + son[1]->cover + 1; } inline bool is_bad() { return max(son[0]->cover, son[1]->cover) > cover*alpha + 5; } inline ll dis(Point p) { if (this == null)return INF; ll res = 0; //曼哈顿距离 ll x=0,y=0; if (p.x<r1.x || p.x>r2.x)x += p.x < r1.x ? r1.x - p.x : p.x - r2.x; if (p.y<r1.y || p.y>r2.y)y += p.y < r1.y ? r1.y - p.y : p.y - r2.y; res=x*x+y*y; return res; } }; Node mempool[N]; Node *tail; Node *root; inline bool cmp(Point p1, Point p2) { if (dimension == 0)return p1.x < p2.x || (p1.x == p2.x && p1.y < p2.y); return p1.y < p2.y || (p1.y == p2.y && p1.x < p2.x); } inline ll Pingfang_sum(Point a,Point b) { if(a.p<b.p) return INF; return 1ll*(a.x - b.x)*(a.x - b.x) + 1ll*(a.y - b.y)*(a.y - b.y); } inline void init() { tail = mempool; null = tail++; null->son[0] = null->son[1] = null; null->r1 = Point(INF, INF ,INF); null->r2 = Point(-INF, -INF,-INF); null->cover = 0; root = null; } inline Node* new_node(Point key) { Node *o; o = tail++; o->son[0] = o->son[1] = null; o->cover= 1; o->p = o->r1 = o->r2 = key; return o; } inline void travel(Node* p, vector<Node*>&x) { if (p == null)return; travel(p->son[0], x); x.push_back(p); travel(p->son[1], x); } inline Node* divide(vector<Node*>&x, int l, int r, bool d) { if (l >= r)return null; int mid = (l + r) >> 1; dimension = d; Node *o = x[mid]; o->son[0] = divide(x, l, mid, d ^ 1); o->son[1] = divide(x, mid + 1, r, d ^ 1); o->maintain(); return o; } inline void rebuild(Node *&o, bool d) { static vector<Node*>v; v.clear(); travel(o, v); o = divide(v, 0, v.size(), d); } inline Node* build(int l, int r, bool d) { if (l >= r)return null; int mid = (l + r) >> 1; dimension = d; nth_element(a + l, a + mid, a + r, cmp); Node *o = new_node(a[mid]); o->son[0] = build(l, mid, d ^ 1); o->son[1] = build(mid + 1, r, d ^ 1); o->maintain(); return o; } inline void query(Node *o, Point key) { if (o == null)return; ll ans_t=Pingfang_sum(key, o->p); if(ans>=ans_t) { if(ans==ans_t) ans_num=min(o->p.p,ans_num); else{ ans_num=o->p.num; ans=ans_t; } } int dir = o->son[0]->dis(key) > o->son[1]->dis(key); query(o->son[dir], key); if (o->son[dir ^ 1]->dis(key) <= ans) query(o->son[dir ^ 1], key); } inline int read() { char ch = getchar(); int f = 1, x = 0; while (ch > '9' || ch < '0') { if (ch == '-')f = -1; ch = getchar(); } while (ch >= '0'&&ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); } return x * f; } Point ans_all[N],q[N],kaishi[N]; int main() { int T; T=read(); while(T--){ init(); int n=read(),m=read(); for(int i=0;i<n;i++){ a[i].x=read();a[i].y=read();a[i].p=read(); a[i].num=i; kaishi[i]=a[i]; } root=build(0, n, 0); for(int i=0;i<m;i++){ q[i].x=read();q[i].y=read();;q[i].p=read(); ans=INF; query(root, q[i]); printf("%d %d %d ",kaishi[ans_num].x,kaishi[ans_num].y,kaishi[ans_num].p); } } }