hdu 5992 kd-tree离线(在线写法常数太大了)

题目大意:

给你二维平面上一些旅馆,每个都有一个价格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);
        }
        
    }
    
    
    
}
原文地址:https://www.cnblogs.com/King-of-Dark/p/12830592.html